Базовый набор ZFS-команд для повседневной работы
Пять команд закрывают большую часть ежедневных задач администратора ZFS: zpool create, zpool status, zfs create, zfs set, zfs list. Добавьте к ним zpool iostat, smartctl и zfs send, и вы получите полный рабочий набор для пула на десятки терабайт.
Синтаксис ниже проверен на OpenZFS 2.3 и новее в Ubuntu 24.04, RHEL 10, TrueNAS SCALE и FreeBSD 14.x. Все операции с пулами выполняются от root или через sudo: делегирование прав командой zfs allow работает на уровне датасетов, а создавать, экспортировать и уничтожать пулы непривилегированный пользователь не может.
| Задача | Команда |
|---|---|
| Создать зеркало | zpool create tank mirror disk1 disk2 |
| Создать RAIDZ2 | zpool create -o ashift=12 tank raidz2 disk1 ... disk6 |
| Создать датасет | zfs create tank/data |
| Включить сжатие | zfs set compression=lz4 tank/data |
| Ограничить объём | zfs set quota=500G tank/data |
| Проверить пул | zpool status -v |
| Проверить место | zfs list -o name,used,avail,refer |
| Проверить нагрузку | zpool iostat -v 5 |
| Сделать снапшот | zfs snapshot tank/data@2026-09-11 |
| Отправить на второй сервер | zfs send -i tank/data@base tank/data@new | ssh backup zfs receive backup/data |
| Проверить диск | smartctl -a /dev/sda |
Имена устройств вида /dev/sdX меняются после перезагрузки, переподключения кабеля или обновления ядра. Собирайте пулы на /dev/disk/by-id/...: тогда zpool status всегда покажет тот физический диск, который вы имели в виду.
Практическое решение: TimeWeb
Создание пула: zpool create
# зеркало: минимум два диска, переживает отказ одного zpool create tank mirror /dev/disk/by-id/ata-DISK-A /dev/disk/by-id/ata-DISK-B # RAIDZ1: минимум три диска, переживает отказ одного zpool create -o ashift=12 tank raidz1 /dev/disk/by-id/ata-DISK-A /dev/disk/by-id/ata-DISK-B /dev/disk/by-id/ata-DISK-C # RAIDZ2: минимум четыре диска, переживает отказ двух zpool create -o ashift=12 -O compression=lz4 tank raidz2 /dev/disk/by-id/ata-DISK-A /dev/disk/by-id/ata-DISK-B /dev/disk/by-id/ata-DISK-C /dev/disk/by-id/ata-DISK-D # страйп: без избыточности, только под временные данные zpool create scratch /dev/disk/by-id/ata-DISK-A /dev/disk/by-id/ata-DISK-B
mirror даёт лучшую скорость на случайных операциях и быстрое восстановление, но платите вы половиной ёмкости. RAIDZ1 разумен на четырёх-пяти дисках, RAIDZ2 и RAIDZ3 берите для массивов от шести дисков и для накопителей объёмом от 8 ТБ, когда resilver растягивается на сутки. Страйп из одиночных vdev отказывает целиком при потере любого диска.
Параметр ashift=12 выставляйте для всех современных накопителей: сектор 512e и 4Kn требует выравнивания по 4 КБ. Пул с ashift=9 выполняет read-modify-write для каждого блока меньше 4 КБ, и скорость случайной записи падает в разы. Изменить ashift после создания пула нельзя, только пересобрать массив.
Флаг -f (force) применяйте осознанно: он перезапишет метки на дисках, которые входят в другой пул или содержат файловую систему. Сравнение ZFS-зеркал с программным RAID на mdadm и LVM приведено в материале о программных RAID-массивах на Linux в 2026 году.
Управление датасетами: zfs create и zfs set
zfs create tank/data zfs create -o mountpoint=/srv/app -o compression=zstd tank/app zfs set compression=lz4 tank/data zfs set recordsize=1M tank/data zfs set quota=500G tank/data zfs set atime=off tank/data zfs set xattr=sa tank/data zfs get compression,recordsize,quota,atime tank/data zfs get -r compression tank
Датасеты наследуют свойства от родителя: общие параметры задают один раз на корне пула, частные переопределяют на конкретном датасете. compression=lz4 включён по умолчанию в OpenZFS 2.x, но после апгрейда пула со старых версий значение легко проверить через zfs get. Для смешанных данных lz4 выигрывает почти всегда, zstd даёт лучшее сжатие ценой нагрузки на CPU.
recordsize влияет только на новые блоки. Датасет под PostgreSQL держите на recordsize=16K, под виртуальные машины, медиафайлы и бэкапы ставьте 1M. Смена recordsize на живом датасете не требует размонтирования, но уже записанные данные перейдут на новый размер только после перезаписи. Свойство atime=off убирает лишние операции записи при чтении и заметно снижает износ SSD.
Просмотр состояния: zpool status и zfs list
zpool status -v zfs list zfs list -o name,used,avail,refer,mountpoint zfs list -t snapshot zpool iostat -v 5
zpool status отвечает на вопрос, жив ли массив. zfs list показывает, куда ушло место. zpool iostat выводит текущую нагрузку в операциях и задержке. Привычка открывать zpool status после любой операции с дисками экономит часы разбирательств.
Создание и удаление пулов не имеют корзины. zpool destroy tank и zfs destroy -r tank/data уничтожают данные сразу, если на другом пуле нет снапшотов или реплики на втором сервере. План безопасного вывода пула из эксплуатации описан в статье о том, как безопасно удалить пул ZFS и подготовить диски к повторному использованию.
Диагностика состояния пулов и дисков
Порядок проверки при первых признаках проблемы: zpool status, затем smartctl по подозрительным дискам, затем dmesg. Такой порядок отсекает ложные тревоги и находит причину за несколько минут.
Чтение zpool status: что означают state, scan и errors
pool: tank
state: DEGRADED
status: One or more devices could not be used because the label is missing
or invalid. Sufficient replicas exist for the pool to continue
functioning in a degraded state.
action: Replace the device using 'zpool replace'.
scan: scrub repaired 0B in 04:12:33 with 0 errors on Sun Sep 6 03:12:44 2026
config:
NAME STATE READ WRITE CKSUM
tank DEGRADED 0 0 0
mirror-0 DEGRADED 0 0 0
sda ONLINE 0 0 0
sdb FAULTED 3 0 0 too many errors
errors: No known data errors
state показывает состояние всего пула: ONLINE, DEGRADED, FAULTED, UNAVAIL, SUSPENDED. DEGRADED означает потерю избыточности: один или несколько vdev работают неполным составом. SUSPENDED тяжелее остальных состояний, пул перестал отдавать данные и требует работы с оборудованием.
Строка scan хранит дату последнего scrub, время выполнения и число исправленных ошибок. Запись «repaired 0B» после регулярных проверок говорит, что битых блоков нет.
Три счётчика READ, WRITE и CKSUM стоят в блоке config. CKSUM растёт, когда контрольные суммы не сходятся и данные восстанавливают с других дисков. Ненулевой CKSUM без роста ошибок чтения часто указывает на кабель, бэкплейн или контроллер, а не на сам накопитель.
Строка errors: No known data errors означает отсутствие известных повреждений. При появлении Permanent errors запустите zpool status -v: команда выведет список файлов и датасетов, которые не удалось восстановить. Такие файлы достают из снапшота или бэкапа, потому что внутри пула исправлять их нечем.
dmesg -T | grep -iE 'ata|nvme|i/o error|medium error|reset'
Вывод dmesg дополняет картину: строки вида medium error и reset controller появляются раньше, чем пул уходит в DEGRADED.
Проверка дисков через smartctl
smartctl -a /dev/sda smartctl -t short /dev/sda smartctl -t long /dev/sda smartctl -a -d sat /dev/sda # диск за USB-мостом smartctl -a /dev/nvme0
| ID | Атрибут | Что означает рост |
|---|---|---|
| 5 | Reallocated_Sector_Ct | Переназначенные секторы: десятки значений означают планирование замены |
| 187 | Reported_Uncorrect | Ошибки, которые накопитель не смог исправить |
| 197 | Current_Pending_Sector | Секторы в ожидании переназначения: любое значение выше нуля это повод менять диск |
| 198 | Offline_Uncorrectable | Секторы, нечитаемые при офлайн-сканировании |
| 199 | UDMA_CRC_Error_Count | Ошибки передачи по интерфейсу: проверьте кабель, порт и питание |
Для NVMe вместо SATA-атрибутов смотрите строки Media and Data Integrity Errors, Available Spare и Percentage Used. Рост UDMA_CRC_Error_Count лечится заменой кабеля или переносом диска на другой порт, списывать накопитель раньше времени не нужно. Короткий тест smartctl -t short занимает пару минут, полный smartctl -t long идёт несколько часов и нагружает диск, поэтому планируйте его на окно обслуживания.
zfs list и zpool iostat: контроль места и нагрузки
zfs list -o space zfs list -o name,used,usedbydataset,usedbychildren,usedbysnapshots,usedbyrefreservation zpool iostat -v 5 zpool iostat -v -l 5
zfs list -o space разбивает used по источникам: сами данные датасета, потомки, снапшоты и резервирование. Снапшоты, которые живут месяцами, нередко занимают больше места, чем рабочие данные. Когда usedbysnapshots забирает треть объёма, пора пересматривать политику хранения.
zpool iostat -v показывает нагрузку по vdev и отдельным дискам. Ориентир по задержке: 1-3 мс для HDD и доли миллисекунды для NVMe. Рост latency при падении bandwidth обычно указывает на износ накопителя, ошибки контроллера или конкуренцию задач. Базовый чек-лист проверки нового пула приведён в руководстве по проверке и обслуживанию ZFS-пула после создания.
Обслуживание пула: scrubbing, resilvering и замена дисков
Scrubbing: плановая проверка целостности
zpool scrub tank zpool status tank # прогресс виден в строке scan zpool scrub -p tank # пауза zpool scrub -s tank # отмена
Scrub читает все блоки и сверяет контрольные суммы, при расхождении данные берутся с другого диска и перезаписываются. Для SATA-дисков достаточно ежемесячной проверки, для SAS и NVMe в нагруженных системах запускайте scrub раз в неделю. На пуле 100 ТБ из HDD проверка идёт 12-20 часов и заметно снижает скорость остальных операций, поэтому ставьте её на ночь или на выходные.
Не запускайте scrub, пока идёт resilvering, и не выключайте сервер посреди проверки: прерванный scrub после перезагрузки начнётся заново. Планировать проверки удобно через cron или systemd timer. В TrueNAS SCALE расписанием заведует отдельный раздел интерфейса, там же настраивают оповещения. Развёрнутая схема такого обслуживания собрана в статье о проактивном обслуживании ZFS в TrueNAS: мониторинг, scrub и замена дисков.
Замена диска: zpool replace и hot spare
zpool offline tank sdb zpool replace tank sdb /dev/disk/by-id/ata-NEW-DISK zpool status tank zpool add tank spare /dev/disk/by-id/ata-SPARE
Порядок для отказавшего диска: отметьте его offline (для уже выпавшего в FAULTED шаг можно пропустить), затем выполните zpool replace с указанием старого и нового устройства. ZFS скопирует данные на новый накопитель и вернёт vdev к полному составу. Команда zpool online нужна, если вы вернули прежний диск в тот же vdev и хотите снова ввести его в работу.
Hot spare лежит в пуле готовым к работе. При отказе диска ZFS автоматически начнёт resilver на запасное устройство, и администратору останется заменить вышедший накопитель. Запасная железка на полке работает не хуже, но требует ручного zpool replace и увеличивает окно без избыточности.
Resilvering: что происходит и как не навредить
Resilver восстанавливает данные на новый диск по контрольным суммам и parity. Сканируется весь занятый объём, поэтому на пуле RAIDZ из дисков по 16 ТБ процесс легко занимает сутки и больше. Прогресс виден в строке scan вывода zpool status: процент, скорость и оставшееся время.
Пока идёт resilver, не запускайте scrub, не добавляйте диски в пул и не устраивайте тесты производительности. Параметры zfs_resilver_min_time_ms (по умолчанию 3000 мс) и zfs_scan_min_time_ms управляют долей времени, которую ZFS отдаёт работе с дисками. Их уменьшение ускоряет восстановление, но сильнее бьёт по отзывчивости пула для рабочих нагрузок. Меняйте настройки только при уверенности в запасе по производительности.
Снапшоты и репликация между системами хранения
Создание и удаление снапшотов
zfs snapshot tank/data@2026-09-11-before-upgrade zfs list -t snapshot zfs list -t snapshot -o name,used,refer tank/data zfs destroy tank/data@2026-09-11-before-upgrade zfs hold keep tank/data@backup-2026-09-01 zfs release keep tank/data@backup-2026-09-01
Снапшот занимает место только тогда, когда данные изменились: сразу после создания used равен нулю. Датасет на 500 ГБ со свежим снапшотом и изменившимися за сутки 2 ГБ займёт под снапшот именно эти 2 ГБ. Чем дольше живёт снапшот и чем активнее меняются данные, тем дороже он обходится.
Именуйте снапшоты с датой и причиной: через месяц вы не вспомните, зачем делали @snap1. Команда zfs hold защищает снапшот от удаления, в том числе от автоматической очистки sanoid. Флаг -r в zfs destroy рекурсивно сносит снапшоты датасета и его потомков, поэтому применяйте его после просмотра списка через zfs list -t snapshot.
Репликация через zfs send и zfs receive
# первичная копия zfs snapshot tank/data@base zfs send tank/data@base | ssh backup.zfs zfs receive backup/data # инкремент: передаются только изменения между снапшотами zfs send -i tank/data@base tank/data@daily-2026-09-11 | ssh backup.zfs zfs receive backup/data # рекурсивно со свойствами и перезаписью цели при расхождении zfs send -R tank/data@daily-2026-09-11 | ssh backup.zfs zfs receive -F backup/data
Ключ -i превращает полную передачу в инкрементальную: поток содержит только блоки, появившиеся между базовым и текущим снапшотом. Первая репликация большого датасета идёт часами, ночные инкременты по 5-10 ГБ проходят за минуты.
Флаг -R переносит датасеты вместе с потомками, свойствами и точками монтирования. Приём в существующий датасет без совпадения снапшотов упадёт, если не добавить -F: этот ключ откатывает целевую сторону до состояния отправителя и уничтожает данные, которых нет в потоке. Перед первой репликацией удостоверьтесь, что на втором сервере хватает места и версия OpenZFS не старше, чем на источнике. Для зашифрованных датасетов используйте zfs send -w с сырым потоком, иначе приём потребует ключа шифрования.
Второй сервер необязательно покупать: под приёмник подойдёт облачная площадка. Timeweb Cloud даёт серверы, хранилище и базы данных, из которых получается удобная офсайт-реплика с оплатой за фактические ресурсы.
Автоматизация: sanoid и syncoid
[tank/data]
use_template = production
recursive = yes
[template_production]
hourly = 36
daily = 30
monthly = 6
autosnap = yes
autoprune = yes
Sanoid создаёт и чистит снапшоты по расписанию из sanoid.conf, syncoid отправляет их на другой сервер. Команда репликации выглядит так:
syncoid --recursive tank/data backup.zfs:data
Запускайте sanoid через systemd timer или cron каждые 15 минут: тогда часовые снапшоты появляются вовремя, а старые удаляются по политике. Логи sanoid и syncoid читайте после каждого изменения конфигурации, иначе молча пропущенная ошибка репликации обнаружится в момент, когда бэкап действительно нужен. Если разбирать длинные логи автоматизации вручную не хочется, поток удобно прогнать через модель: AiTunnel даёт единый доступ к популярным нейросетям с оплатой в рублях и без VPN.
Расширение пула и управление квотами
Добавление дисков: zpool add и zpool attach
# расширить существующее зеркало: было два диска, станет три zpool attach tank /dev/disk/by-id/ata-OLD /dev/disk/by-id/ata-NEW # добавить новый vdev, например второе зеркало zpool add tank mirror /dev/disk/by-id/ata-A /dev/disk/by-id/ata-B # точка отката перед рискованной операцией zpool checkpoint tank
zpool attach вводит диск в существующий vdev: зеркало из двух дисков становится зеркалом из трёх, избыточность растёт. zpool add создаёт новый vdev верхнего уровня, и пул начинает распределять блоки между ними. Второй вариант опасен добавлением страйпа без избыточности: его отказ уносит весь пул.
Одиночный диск в zpool add это распространённая ошибка. Добавляйте сразу зеркало или RAIDZ, даже если это удваивает расход железа.
RAIDZ долго не расширялся: добавить диск в существующий raidz1 vdev было нельзя, требовалась пересборка пула. В OpenZFS 2.3 появилась штатная RAIDZ expansion, и команда zpool attach tank raidz1-0 /dev/disk/by-id/ata-NEW добавляет диск к живому vdev. Процесс идёт постепенно, старые блоки сохраняют прежнюю ширину, поэтому свободное место прибавляется по мере перезаписи данных. На версиях до 2.3 такого механизма нет, и там расширение RAIDZ делают переносом на новый пул.
zpool checkpoint фиксирует состояние пула и позволяет вернуться к нему через zpool import --rewind-to-checkpoint. Точку отката стоит ставить перед zpool add, заменой дисков и любыми экспериментами. Checkpoint удерживает освободившееся место, поэтому удаляйте его командой zpool checkpoint -d tank, когда операция прошла успешно.
Квоты и резервирование: zfs set quota и reservation
zfs set quota=1T tank/data zfs set quota=100G tank/home zfs set userquota=50G tank/home zfs set reservation=100G tank/vm zfs set refreservation=200G tank/zvol zfs get quota,reservation,used,available tank/data
quota ограничивает максимальный объём датасета вместе с потомками. Своего значения квоты дети не наследуют: данные дочернего датасета считаются в лимит родителя, а собственный лимит ему задают явно. Свойства userquota и groupquota ограничивают объём, который может занять конкретный пользователь или группа.
reservation гарантирует датасету место в пуле: зарезервированный объём не отдадут другим, даже если датасет его не использует. Для zvol применяйте refreservation, оно резервирует место под весь объём тома. Оба свойства уменьшают доступную ёмкость, и zpool list покажет больше занятого места, чем zfs list.
Квота ниже текущего объёма данных не удаляет файлы, но блокирует новые записи: приложение получит ENOSPC. Перед снижением лимита проверьте вывод zfs list -o space и удалите лишние снапшоты.
Типичные ошибки и как их избежать
Ошибки при создании и расширении пула
| Ошибка | Последствие | Как правильно |
|---|---|---|
| zpool create tank sda sdb без mirror | Страйп: отказ любого диска убивает пул | zpool create tank mirror /dev/disk/by-id/A /dev/disk/by-id/B |
| ashift=9 на дисках 4K | read-modify-write, падение случайной записи | -o ashift=12 при создании пула |
| zpool add tank sdc вместо attach | Новый vdev без избыточности, риск для всего пула | zpool add tank mirror sdc sdd |
| Имена /dev/sdX в конфигурации | После перезагрузки пул собирается из других устройств | /dev/disk/by-id/... и проверка zpool status |
| recordsize=128K по умолчанию под базу данных | Рост задержки и объёма записи | zfs set recordsize=16K перед заливкой данных |
Отдельно стоит проверить состав пула перед переносом данных: лишний страйп или потерянный диск в конфигурации видны только в zpool status. Общая картина возможностей и ограничений технологии собрана в статье о ZFS в программных системах хранения: возможности, ограничения и типовые ошибки.
Ошибки при обслуживании и замене дисков
| Ошибка | Последствие | Как правильно |
|---|---|---|
| Вынуть диск без zpool offline | Пул уходит в DEGRADED, часть чтений падает с ошибкой | zpool offline tank sdb, затем извлечение |
| Scrub во время resilvering | Конкуренция за диски, окно без избыточности растягивается | Дождаться завершения resilver, потом scrub |
| Перезагрузка до конца resilver | Процесс начинается заново, для RAIDZ это часы и сутки | Следить за zpool status до ONLINE и нулевого scan |
| Игнорирование CKSUM и slow I/O | Потеря избыточности остаётся незамеченной | Проверка zpool status после каждого события с железом |
| zfs destroy -r по снапшотам | Рекурсивное удаление всех снапшотов без возврата | Удалять без -r и после zfs list -t snapshot |
| autotrim=on на дешёвых SATA SSD | Просадки производительности у части контроллеров | Тестировать под нагрузкой, при деградации вернуть off |
Перед любой рискованной операцией делайте снапшот и zpool checkpoint, а изменения проверяйте на тестовом стенде: импорт копии пула в режиме zpool import -o readonly=on показывает, как поведёт себя конфигурация, и не трогает рабочие данные.