---
tags: [freebsd, tooling]
verified: 2026-09-02
---

# FreeBSD — ZFS: файловая система, которая меняет правила

## Обзор

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.

```sh
# 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) — файловая система внутри пула. Датасеты — иерархические: дочерние наследуют свойства от родительских. Создание датасета — мгновенная операция, не требующая выделения пространства.

```sh
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 создаёт такую структуру:

```text
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. Они наследуются от родительских датасетов, но могут быть переопределены на любом уровне.

```sh
zfs get all zroot/home               # все свойства
zfs get compression zroot            # конкретное свойство
zfs set compression=lz4 zroot        # установить (наследуется дочерними)
zfs inherit compression zroot/tmp    # вернуть к наследуемому значению
```

### Практически важные свойства

```sh
# Сжатие — включать ВСЕГДА (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, создание снепшота — атомарная операция за доли секунды, независимо от размера данных. Место занимают только блоки, изменённые после создания снепшота.

```sh
# Создать снепшот
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:

```sh
# /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), занимает место только для изменённых блоков.

```sh
zfs snapshot zroot/jails/templates/15.1-RELEASE@base
zfs clone zroot/jails/templates/15.1-RELEASE@base zroot/jails/web
```

Клон зависит от родительского снепшота — снепшот нельзя удалить, пока существует клон. `zfs promote` разрывает эту зависимость, делая клон независимым датасетом:

```sh
zfs promote zroot/jails/web
# Теперь зависимость инвертирована: оригинал зависит от (бывшего) клона
```

Основное применение клонов — jail'ы (описано в статье о jails) и быстрое создание тестовых окружений.

## Send / Receive: репликация и бэкапы

`zfs send` сериализует снепшот в поток байт, `zfs receive` воссоздаёт датасет из этого потока. Это основной механизм бэкапов и репликации в ZFS.

### Полный send

```sh
# Бэкап на локальный файл
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 — инкрементальная репликация. Передаются только блоки, изменённые между двумя снепшотами:

```sh
# Первый полный бэкап
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

```sh
# Рекурсивно — все дочерние датасеты и их снепшоты
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.

```sh
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

```sh
# Экспорт (полный бэкап системы в один файл)
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) — автоматически исправляет повреждённые блоки.

```sh
zpool scrub zroot                    # запустить scrub
zpool status                         # прогресс и результаты

# Автоматический scrub — через periodic
# /etc/periodic.conf
daily_scrub_zfs_enable="YES"
```

На production рекомендуется запускать scrub минимум раз в месяц. На VPS с одним диском scrub не может исправить ошибки (нет избыточности), но обнаружит их — что уже ценно.

### Полезные команды мониторинга

```sh
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` — это нормально, разница объясняется снепшотами и дочерними датасетами.

```sh
# Что занимает место? Подробная разбивка
zfs list -o name,used,usedbydataset,usedbysnapshots,usedbychildren zroot
```

## Делегирование: ZFS без root

ZFS позволяет делегировать управление конкретным датасетом непривилегированному пользователю:

```sh
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 работают приложения со своими кэшами.

```sh
# /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. На чистом файл-сервере — пусть берёт сколько хочет.

```sh
# Текущий размер 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

```sh
# /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-специфика.

```sh
# Датасет для каждого 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:

```sh
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/](https://docs.freebsd.org/en/books/handbook/zfs/)
- FreeBSD Foundation, "An Introduction to ZFS": [freebsdfoundation.org/resource/an-introduction-to-the-z-file-system/](https://freebsdfoundation.org/resource/an-introduction-to-the-z-file-system/)
- Klara Systems, "Managing Boot Environments": [klarasystems.com/articles/managing-boot-environments/](https://klarasystems.com/articles/managing-boot-environments/)
- `zpool(8)`: [man.freebsd.org/cgi/man.cgi?query=zpool&sektion=8](https://man.freebsd.org/cgi/man.cgi?query=zpool&sektion=8)
- `zfs(8)`: [man.freebsd.org/cgi/man.cgi?query=zfs&sektion=8](https://man.freebsd.org/cgi/man.cgi?query=zfs&sektion=8)
- `bectl(8)`: [man.freebsd.org/cgi/man.cgi?query=bectl&sektion=8](https://man.freebsd.org/cgi/man.cgi?query=bectl&sektion=8)
- OpenZFS documentation: [openzfs.github.io/openzfs-docs/](https://openzfs.github.io/openzfs-docs/)

---

## Связанные заметки

- [FreeBSD — обновление системы](./freebsd-updating.md) — boot environments как страховка при обновлении
- [FreeBSD — Jails](./freebsd-jails.md) — датасет на jail, клоны и снепшоты
- [FreeBSD — мониторинг и отладка](./freebsd-monitoring-debugging.md) — статистика ARC и диагностика пулов
- [Linux — файловые системы: ext4, XFS, Btrfs, LVM](./linux-filesystems.md) — Btrfs и LVM, для сравнения с ZFS
- [FreeBSD — сводный cheatsheet](./freebsd-cheatsheet.md) — быстрая справка по zpool и zfs
- [SATA, SAS и NVMe](./storage-interfaces.md) — из чего собирать пул: двойные порты SAS, T10 PI, NVMe под special vdev
- [Резервное копирование: стратегия и проверка восстановления](./backup-strategy.md) — где кончается снепшот и начинается бэкап; границы `zfs send` как offsite-схемы
- [FreeBSD — bhyve: виртуализация после jails](./freebsd-bhyve.md) — zvol под диски гостей и снепшот как механизм отката виртуалки
- [Восстановление незагружающейся системы](./system-recovery.md) — `zpool import -f -R` и откат снепшота, когда система не грузится
