Обзор
ZFS — не просто файловая система, а объединение файловой системы и менеджера томов в одном. Она устраняет необходимость в отдельных слоях: партиционировании, RAID-контроллерах, LVM, fsck. Всё это — часть ZFS. Данные защищены контрольными суммами на каждом блоке, повреждения обнаруживаются и (при наличии избыточности) исправляются автоматически.
ZFS разработана в Sun Microsystems (2005), открыта под CDDL, портирована в FreeBSD в версии 7.0 (2008). С тех пор FreeBSD стала одной из основных платформ для ZFS — начиная с FreeBSD 13, ZFS (через OpenZFS) является файловой системой по умолчанию в инсталляторе. Версия OpenZFS в базе жёстко привязана к ветке: 14.x несёт 2.2.x (14.4-RELEASE — 2.2.9), 15.x — уже 2.4.x (15.0 вышла с 2.4.0-rc4, 15.1 — с 2.4.2), и набор фич у этих веток заметно разный. Netflix, iXsystems (TrueNAS), Joyent — все работают на FreeBSD + ZFS.
Статья построена от концепций к практике: сначала архитектура (пулы, vdev'ы, датасеты), затем повседневные операции, затем продвинутые возможности (send/receive, boot environments, делегирование).
Архитектура: пулы, vdev'ы, датасеты
Уровень хранения: zpool и vdev
zpool — пул хранения. Это фундамент ZFS: всё дисковое пространство объединяется в пул, а файловые системы (датасеты) создаются поверх него и разделяют общее пространство. Нет необходимости заранее решать, сколько места выделить под /var или /home — пул динамически распределяет пространство.
Пул состоит из одного или нескольких vdev (virtual device). Тип vdev определяет уровень избыточности:
stripe — без избыточности. Потеря одного диска = потеря всего пула. Подходит для VPS с единственным диском (выбора нет) или для временных данных.
mirror — зеркалирование. Данные записываются на все диски в зеркале. Потеря одного диска — пул продолжает работать. Минимум 2 диска, можно добавлять диски в зеркало на лету.
raidz1 / raidz2 / raidz3 — аналоги RAID-5/6 с одной/двумя/тремя дисками чётности. Для серверов с несколькими дисками. raidz2 — наиболее популярный баланс между ёмкостью и надёжностью.
Тип vdev задаётся при создании, и менять его в общем случае нельзя, но два исключения существенны. Одиночный диск всегда можно превратить в зеркало: zpool attach к не-зеркальному vdev автоматически превращает его в two-way mirror и запускает resilver — так это описано и в 14.x, и в 15.x, никакой новой фичи для этого не нужно. А начиная с OpenZFS 2.3 тот же zpool attach принимает в качестве цели raidz-группу (фича raidz_expansion): все размещённые данные перечитываются и переписываются на расширенный набор дисков, избыточность сохраняется на протяжении всей операции, но уровень защиты не растёт — raidz2 после расширения остаётся raidz2, а старые блоки сохраняют прежнее соотношение данных к чётности. В базовой системе это доступно начиная с FreeBSD 15.0; в 14.x с OpenZFS 2.2 расширения raidz нет. Удалить top-level vdev (zpool remove) можно только в пуле, где нет ни одного raidz- или draid-vdev и у всех vdev'ов одинаковый ashift.
# VPS с одним диском (типичный случай)
zpool create zroot /dev/vtbd0p3
# Два диска — зеркало
zpool create tank mirror /dev/da0 /dev/da1
# Четыре диска — raidz1
zpool create tank raidz1 /dev/da0 /dev/da1 /dev/da2 /dev/da3
# Статус пула
zpool status
zpool list
Уровень данных: датасеты
Датасет (dataset) — файловая система внутри пула. Датасеты — иерархические: дочерние наследуют свойства от родительских. Создание датасета — мгновенная операция, не требующая выделения пространства.
zfs create zroot/home
zfs create zroot/var/log
zfs create zroot/jails
zfs create zroot/jails/web
Каждый датасет автоматически монтируется по пути, соответствующему его имени (zroot/var/log → /var/log). Это можно переопределить свойством mountpoint.
Ключевой принцип: создавать датасет для каждого логически отдельного набора данных. Не один датасет на всё, а отдельные для /home, /var/log, /usr/local, каждого jail. Это позволяет: задавать разные свойства (сжатие, квоты), делать снепшоты и send/receive отдельных частей, управлять квотами независимо.
Типичная разметка VPS
Инсталлятор FreeBSD при выборе ZFS создаёт такую структуру:
zroot # корень пула
zroot/ROOT # контейнер для boot environments
zroot/ROOT/default # активная boot environment (корневая ФС)
zroot/home # /home
zroot/tmp # /tmp
zroot/usr # /usr (canmount=off — не монтируется сам)
zroot/usr/ports # /usr/ports
zroot/usr/src # /usr/src
zroot/var # /var (canmount=off)
zroot/var/audit # /var/audit
zroot/var/crash # /var/crash
zroot/var/log # /var/log
zroot/var/mail # /var/mail
zroot/var/tmp # /var/tmp
canmount=off на zroot/usr и zroot/var означает, что эти датасеты сами не монтируются — они существуют как контейнеры для дочерних датасетов с правильными точками монтирования. Файлы в /usr, не попадающие в дочерние датасеты, хранятся в boot environment.
До FreeBSD 14.0 инсталлятор создавал zroot/usr/home, а /home был симлинком на /usr/home. С 14.0 домашние каталоги вынесены в отдельный датасет zroot/home с mountpoint=/home — специально для того, чтобы они были общими для всех boot environment'ов.
Свойства датасетов
Свойства — центральный механизм управления в ZFS. Они наследуются от родительских датасетов, но могут быть переопределены на любом уровне.
zfs get all zroot/home # все свойства
zfs get compression zroot # конкретное свойство
zfs set compression=lz4 zroot # установить (наследуется дочерними)
zfs inherit compression zroot/tmp # вернуть к наследуемому значению
Практически важные свойства
# Сжатие — включать ВСЕГДА (lz4 практически бесплатен по CPU)
zfs set compression=lz4 zroot
# zstd — лучшее сжатие, чуть дороже по CPU
zfs set compression=zstd zroot/var/log
# Квоты — ограничить размер датасета
zfs set quota=10G zroot/home # жёсткий лимит
zfs set refquota=8G zroot/home # лимит без учёта снепшотов
# Резервация — гарантировать доступное пространство
zfs set reservation=2G zroot/var/log # зарезервировать 2GB
# Запись (recordsize) — влияет на производительность
zfs set recordsize=16K zroot/data/postgresql # для БД: меньше recordsize
zfs set recordsize=1M zroot/data/media # для больших файлов: больше
# Отключить atime — снижает нагрузку на запись
zfs set atime=off zroot
# Readonly
zfs set readonly=on zroot/jails/templates/15.1-RELEASE
compression=lz4 — самый важный совет по ZFS. lz4 настолько быстр, что сжатие часто ускоряет систему: меньше данных записывается/читается с диска. Включать на корне пула — наследуется всеми датасетами. Правда, начиная с OpenZFS 2.2 (то есть во всех живых ветках FreeBSD) значение свойства по умолчанию — уже compression=on, а on при включённой фиче lz4_compress и означает lz4; явная установка теперь нужна главным образом чтобы зафиксировать конкретный алгоритм и не зависеть от того, что ZFS сочтёт разумным дефолтом завтра.
recordsize — размер блока записи. Дефолт 128K оптимален для общего использования. Для баз данных (PostgreSQL, MySQL) рекомендуется 8K-16K (соответствует размеру страницы БД). Для медиа-файлов и больших файлов — 1M.
quota vs refquota: quota ограничивает датасет включая его снепшоты, refquota — только "живые" данные. Для jail'ов обычно нужен quota (чтобы снепшоты не съели всё пространство).
Снепшоты
Снепшот — read-only мгновенная копия датасета на момент создания. Благодаря copy-on-write, создание снепшота — атомарная операция за доли секунды, независимо от размера данных. Место занимают только блоки, изменённые после создания снепшота.
# Создать снепшот
zfs snapshot zroot/home@before-upgrade
zfs snapshot -r zroot/jails@daily-2026-02-24 # рекурсивно (все дочерние)
# Список снепшотов
zfs list -t snapshot
zfs list -t snapshot -o name,used,creation -s creation # сортировка по дате
# Доступ к файлам снепшота (без rollback!)
ls /home/.zfs/snapshot/before-upgrade/
# Rollback — вернуть датасет к состоянию снепшота
zfs rollback zroot/home@before-upgrade
# Внимание: все данные после снепшота БУДУТ ПОТЕРЯНЫ
# Удалить снепшот
zfs destroy zroot/home@before-upgrade
Каталог .zfs/snapshot/ — виртуальный каталог, доступный внутри каждого датасета. Через него можно восстановить отдельный файл без rollback всего датасета — просто скопировать файл из снепшота.
Автоматические снепшоты
filesystems/zfs-periodic или filesystems/zfs-snap-diff из пакетов. Простейший вариант — cron:
# /etc/crontab
# Ежечасные снепшоты, хранить 24
0 * * * * root /sbin/zfs snapshot -r zroot/home@hourly-$(date +\%Y\%m\%d\%H)
# Ежедневные, хранить 30
0 0 * * * root /sbin/zfs snapshot -r zroot@daily-$(date +\%Y\%m\%d)
# Удаление старых: сортируем от новых к старым и сносим всё после 24-го
# (head -n -24 в стиле GNU не годится — head(1) во FreeBSD не принимает отрицательный счётчик)
15 0 * * * root /sbin/zfs list -H -t snapshot -o name -S creation | grep @hourly | tail -n +25 | xargs -n1 zfs destroy
Более зрелое решение — filesystems/zfsnap из пакетов, который управляет TTL снепшотов автоматически. Категорию стоит запомнить: в ноябре 2024 ZFS-порты (zfsnap, zfstools, zfs-periodic, zrepl и прочие) переехали из sysutils в новую категорию filesystems, так что старые пути из статей и рецептов уже не работают.
Клоны
Клон — writable-копия снепшота. Создаётся мгновенно (copy-on-write), занимает место только для изменённых блоков.
zfs snapshot zroot/jails/templates/15.1-RELEASE@base
zfs clone zroot/jails/templates/15.1-RELEASE@base zroot/jails/web
Клон зависит от родительского снепшота — снепшот нельзя удалить, пока существует клон. zfs promote разрывает эту зависимость, делая клон независимым датасетом:
zfs promote zroot/jails/web
# Теперь зависимость инвертирована: оригинал зависит от (бывшего) клона
Основное применение клонов — jail'ы (описано в статье о jails) и быстрое создание тестовых окружений.
Send / Receive: репликация и бэкапы
zfs send сериализует снепшот в поток байт, zfs receive воссоздаёт датасет из этого потока. Это основной механизм бэкапов и репликации в ZFS.
Полный send
# Бэкап на локальный файл
zfs send zroot/data@backup1 > /backup/data-backup1.zfs
# Бэкап на удалённый сервер через SSH
zfs send zroot/data@backup1 | ssh backup-server zfs receive tank/backups/data
# Сжатый бэкап
zfs send zroot/data@backup1 | xz -3 > /backup/data-backup1.zfs.xz
Инкрементальный send
Основная сила send/receive — инкрементальная репликация. Передаются только блоки, изменённые между двумя снепшотами:
# Первый полный бэкап
zfs snapshot zroot/data@monday
zfs send zroot/data@monday | ssh backup zfs receive tank/data
# Инкрементальный (только изменения)
zfs snapshot zroot/data@tuesday
zfs send -i zroot/data@monday zroot/data@tuesday | ssh backup zfs receive tank/data
# -I (заглавная) — включить все промежуточные снепшоты
zfs send -I zroot/data@monday zroot/data@friday | ssh backup zfs receive tank/data
Для VPS это означает: один полный бэкап при настройке, затем ежедневные инкрементальные, передающие только изменения. На 50GB датасете с 200MB ежедневных изменений инкрементальный send занимает секунды.
Рекурсивный send
# Рекурсивно — все дочерние датасеты и их снепшоты
zfs send -R zroot/jails@daily | ssh backup zfs receive -F tank/jails
-R (replicate) — отправить датасет со всеми дочерними и всеми снепшотами. -F (force) на принимающей стороне — удалить датасеты/снепшоты, отсутствующие в потоке, для точной синхронизации.
Boot Environments
Boot environment (BE) — снепшот/клон корневого датасета, из которого можно загрузить систему. Это "undo" для обновлений ОС и пакетов.
bectl(8) — утилита управления BE, входит в base system начиная с FreeBSD 12.0.
bectl list # список BE
# BE Active Mountpoint Space Created
# default NR / 1.2G 2025-12-01 10:00
# Создать BE перед обновлением
bectl create before-upgrade
# Обновить систему
freebsd-update fetch install
pkg upgrade
# Если что-то пошло не так — откатить
bectl activate before-upgrade
reboot
# В меню загрузчика: опция 8 (Boot Environments) — выбрать нужный BE
freebsd-update автоматически создаёт BE перед обновлением, если система на ZFS. Но создавать BE вручную перед pkg upgrade — хорошая привычка.
Экспорт/импорт BE
# Экспорт (полный бэкап системы в один файл)
bectl export default | xz -3 > /backup/system-2026-02-24.be.xz
# Импорт (восстановление — даже на чистой установке)
xzcat /backup/system-2026-02-24.be.xz | bectl import restored
bectl activate restored
reboot
Это самый простой способ полного бэкапа FreeBSD-системы на ZFS. Один файл содержит всю ОС с пакетами и конфигурацией (но не данные из отдельных датасетов вроде /home — они не часть BE).
Мониторинг и обслуживание
Scrub — проверка целостности
Scrub — фоновая проверка контрольных сумм всех данных в пуле. Обнаруживает silent corruption (bit rot). При наличии избыточности (mirror, raidz) — автоматически исправляет повреждённые блоки.
zpool scrub zroot # запустить scrub
zpool status # прогресс и результаты
# Автоматический scrub — через periodic
# /etc/periodic.conf
daily_scrub_zfs_enable="YES"
На production рекомендуется запускать scrub минимум раз в месяц. На VPS с одним диском scrub не может исправить ошибки (нет избыточности), но обнаружит их — что уже ценно.
Полезные команды мониторинга
zpool status # состояние пулов, ошибки, scrub
zpool list # пулы: размер, использование, health
zpool list -v # с разбивкой по vdev
zpool iostat 5 # I/O статистика каждые 5 сек
zpool history # история всех операций с пулом
zfs list # датасеты: used, avail, refer, mountpoint
zfs list -t snapshot # все снепшоты
zfs list -o name,used,compressratio # с показателем сжатия
zfs get compressratio zroot # коэффициент сжатия
Пространство: used, refer, avail
USED — общее пространство, занятое датасетом, включая дочерние датасеты и снепшоты.
REFER — пространство, занятое только "живыми" данными самого датасета (без дочерних и снепшотов).
AVAIL — доступное пространство в пуле.
Распространённая путаница: zfs list показывает USED значительно больше REFER — это нормально, разница объясняется снепшотами и дочерними датасетами.
# Что занимает место? Подробная разбивка
zfs list -o name,used,usedbydataset,usedbysnapshots,usedbychildren zroot
Делегирование: ZFS без root
ZFS позволяет делегировать управление конкретным датасетом непривилегированному пользователю:
zfs allow -u deployer create,destroy,mount,snapshot zroot/jails/web
# Пользователь deployer теперь может создавать снепшоты, монтировать и т.д.
# без root-привилегий
zfs allow zroot/jails/web # показать текущие делегирования
zfs unallow -u deployer zroot/jails/web # отозвать
Полезно для CI/CD: деплой-скрипт может создавать снепшоты перед обновлением и откатываться при ошибках — без sudo/doas.
Тюнинг ZFS на VPS
ARC (Adaptive Replacement Cache)
ARC — кэш чтения ZFS в RAM. По умолчанию его потолок — большее из двух: «вся память минус 1 GiB» и 5/8 всей памяти, то есть практически вся доступная RAM. На VPS с ограниченной RAM (2-4GB) это проблема, если рядом с ZFS работают приложения со своими кэшами.
# /boot/loader.conf
vfs.zfs.arc.max="1073741824" # 1GB — для 2GB VPS
vfs.zfs.arc.max="2147483648" # 2GB — для 4GB VPS
Эмпирика: на VPS с PostgreSQL/Redis оставлять ARC 25-50% RAM. На чистом файл-сервере — пусть берёт сколько хочет.
# Текущий размер ARC
sysctl vfs.zfs.arc.max
sysctl kstat.zfs.misc.arcstats.size # текущее потребление
Имена sysctl в OpenZFS сгруппированы по подсистемам, и старые плоские варианты (vfs.zfs.arc_max, vfs.zfs.arc_min, vfs.zfs.min_auto_ashift и родня) остались только как совместимость: они помечены в коде как LEGACY и при записи печатают в консоль предупреждение о том, что параметр устарел. В новых конфигах пишутся точечные имена — vfs.zfs.arc.max, vfs.zfs.vdev.min_auto_ashift.
Другие tunables
# /boot/loader.conf
vfs.zfs.txg.timeout=5 # интервал сброса транзакционных групп (дефолт 5)
vfs.zfs.prefetch.disable=0 # prefetch — полезен для последовательного чтения
# /etc/sysctl.conf (runtime)
vfs.zfs.vdev.min_auto_ashift=12 # минимальный размер сектора: 4K (для modern drives)
ZFS + Jails: интеграция
Связь подробно описана в статье о jails, здесь — ZFS-специфика.
# Датасет для каждого jail
zfs create -o quota=10G zroot/jails/web
zfs create -o quota=5G zroot/jails/db
# Мгновенное клонирование jail из шаблона
zfs snapshot zroot/jails/templates/15.1-RELEASE@base
zfs clone zroot/jails/templates/15.1-RELEASE@base zroot/jails/web
# Снепшот перед обновлением jail
zfs snapshot zroot/jails/web@before-pkg-upgrade
jexec web pkg upgrade
# Если что-то сломалось:
zfs rollback zroot/jails/web@before-pkg-upgrade
jailed — свойство датасета, позволяющее делегировать управление ZFS внутрь jail:
zfs set jailed=on zroot/jails/web/data
# Теперь внутри jail можно создавать снепшоты этого датасета
В FreeBSD 15.0 у jail(8) появился параметр zfs.dataset — список датасетов, отдаваемых jail'у прямо из его конфигурации (требует allow.mount.zfs). До этого связку приходилось собирать вручную через zfs jail после старта jail'а; в 14.x параметра ещё нет.
Отличия от Linux (OpenZFS)
OpenZFS — тот же код, но интеграция с системой отличается. В FreeBSD ZFS — first-class citizen: boot с ZFS из коробки (загрузчик понимает ZFS), bectl в base system, zfs_enable="YES" в rc.conf, deep интеграция с jails. В Linux ZFS — out-of-tree модуль ядра (лицензионные причины: CDDL vs GPL), загрузка с ZFS требует initramfs/dracut, нет нативного аналога bectl (есть zsys от Ubuntu, но заброшен).
Практическое следствие: на FreeBSD ZFS "просто работает" с минимальной конфигурацией. На Linux — требует больше внимания к установке, обновлению модуля, и совместимости с ядром.
Источники
- FreeBSD Handbook, Chapter 23 "The Z File System (ZFS)": docs.freebsd.org/en/books/handbook/zfs/
- FreeBSD Foundation, "An Introduction to ZFS": freebsdfoundation.org/resource/an-introduction-to-the-z-file-system/
- Klara Systems, "Managing Boot Environments": klarasystems.com/articles/managing-boot-environments/
zpool(8): man.freebsd.org/cgi/man.cgi?query=zpool&sektion=8zfs(8): man.freebsd.org/cgi/man.cgi?query=zfs&sektion=8bectl(8): man.freebsd.org/cgi/man.cgi?query=bectl&sektion=8- OpenZFS documentation: openzfs.github.io/openzfs-docs/
Связанные заметки
- FreeBSD — обновление системы — boot environments как страховка при обновлении
- FreeBSD — Jails — датасет на jail, клоны и снепшоты
- FreeBSD — мониторинг и отладка — статистика ARC и диагностика пулов
- Linux — файловые системы: ext4, XFS, Btrfs, LVM — Btrfs и LVM, для сравнения с ZFS
- FreeBSD — сводный cheatsheet — быстрая справка по zpool и zfs
- SATA, SAS и NVMe — из чего собирать пул: двойные порты SAS, T10 PI, NVMe под special vdev
- Резервное копирование: стратегия и проверка восстановления — где кончается снепшот и начинается бэкап; границы
zfs sendкак offsite-схемы - FreeBSD — bhyve: виртуализация после jails — zvol под диски гостей и снепшот как механизм отката виртуалки
- Восстановление незагружающейся системы —
zpool import -f -Rи откат снепшота, когда система не грузится
Из библиотеки института уносят только знания. Читателей здесь не считают: посещение не регистрируется, отметок в издании не остаётся, счётчиков нет ни у одного издания фонда.
Издание пополняется и пересверяется. Текст доступен на условиях CC BY-SA 4.0 — унесённое можно передавать дальше на тех же условиях.