Если вы администрируете проекты на VDS и упёрлись в ограничения классических файловых систем, самое время посмотреть в сторону ZFS. Сильные стороны ZFS — контроль целостности, копирование при записи (CoW), мгновенные снимки, инкрементальная репликация и встроенное сжатие — особенно ценны на виртуальных серверах, где каждая операция ввода‑вывода и мегабайт переданного трафика стоят денег и времени.
В этой статье — практический разбор, как развернуть ZFS на VDS, рационально организовать структуру датасетов для веб‑проектов и БД, включить lz4, построить политику snapshots и репликации send/receive, а также избежать типичных ловушек: от неконтролируемого роста снапшотов до переполнения пула.
Когда ZFS на VDS имеет смысл
Даже с одним виртуальным диском ZFS приносит ощутимую пользу. Наиболее частые причины выбора:
- Быстрые и почти бесплатные по времени snapshots, моментальные откаты и клоны для тестов.
- Инкрементальные бэкапы через send/receive — экономия трафика и времени на резервирование.
- Сжатие lz4: уменьшаем нагрузку на диск и сеть, повышаем эффективность на текстовых данных.
- Проверка целостности и самовосстановление повреждённых блоков при наличии копий.
Что важно понимать: на VDS у вас часто один виртуальный диск без избыточности на уровне пула. Значит, отказоустойчивость достигается не зеркалированием в пределах пула, а регулярной репликацией на другой сервер или хранилище. ZFS в таком сценарии закрывает вопросы скорости и удобства бэкапа.
Ресурсы VDS: память, CPU и диск
ZFS использует ARC — кэш в памяти. На VDS с 2–4 ГБ ОЗУ имеет смысл ограничить ARC, чтобы процессам БД и PHP не было тесно. Типовые значения: 256–1024 МБ на небольших машинах. CPU‑накладные расходы lz4 близки к нулю для типичного веб‑нагрузочного профиля, а выигрыш по I/O и сети зачастую перекрывает издержки.
Хранилище на VDS чаще всего SSD‑бэкенд в облаке с virtio‑blk или virtio‑scsi внутри гостя. Важно создать пул с правильным выравниванием блоков. Для современных SSD выставляйте ashift=12 (4K‑секторы). Не забудьте включить автотрим на пуле, чтобы освобождённые блоки возвращались гипервизору.
Если выбираете размер машины под ZFS и БД, полезно ориентироваться на практику подбора ресурсов — смотрите разбор «Как выбрать план VDS по CPU и RAM» в материале подбора конфигурации VDS.
Установка ZFS и базовое включение
На Ubuntu и Debian достаточно штатных пакетов. После установки загрузите модуль и убедитесь, что всё работает.
sudo apt update
sudo apt install zfsutils-linux
sudo modprobe zfs
zpool version
zfs version
Если у вас один системный диск, а ZFS нужен для данных, имеет смысл выделить под пул отдельный дополнительный диск/том (например, /dev/vdb). Создание пула с полезными свойствами по умолчанию:
sudo zpool create -o ashift=12 -o autotrim=on -O compression=lz4 -O atime=off -O xattr=sa -O acltype=posixacl -O mountpoint=/srv zdata /dev/vdb
zpool status
zfs list
Ключевые моменты:
autotrim=on— регулярная передача TRIM гипервизору.atime=off— не обновлять время доступа, уменьшаем лишние записи.xattr=sa— хранить расширенные атрибуты эффективнее.compression=lz4— безопасное сжатие по умолчанию.
Если второй диск отсутствует, создавать пул из файла‑vdev не рекомендуется для продакшена. Лучше дождаться отдельного диска или мигрировать данные на отдельный том.
Структура датасетов под типичный стек
Разделяйте данные по профилю I/O: это позволяет гибко настраивать свойства и квоты, а также удобно делать выборочные снапшоты и репликацию.
# Корень данных проекта
sudo zfs create zdata/project
# Веб‑корень: большие файлы, кеши, статика
sudo zfs create -o recordsize=128K zdata/project/www
# Базы данных (MySQL/MariaDB): 16K блок
sudo zfs create -o recordsize=16K -o logbias=latency zdata/project/mysql
# PostgreSQL: обычно 8K или 16K, проверяйте PAGE_SIZE сборки
sudo zfs create -o recordsize=8K -o logbias=latency zdata/project/pg
# Логи: не всегда нужен snapshot, лучше ограничить рост
sudo zfs create -o recordsize=128K zdata/project/logs
sudo zfs set quota=5G zdata/project/logs
Зачем разные recordsize? ZFS с CoW хранит данные блоками. Чем ближе размер блока к реальному паттерну записи приложения, тем меньше лишних переписываний и фрагментации. Для InnoDB (обычно 16K) попадание по размеру критично; для статического контента выгоднее крупные блоки (128K).
Свойство logbias=latency помогает рабочим нагрузкам с синхронными записями (БД). Никогда не отключайте sync для баз в продакшене: это чревато потерей данных при сбоях.

Ограничение ARC на VDS с малой памятью
По умолчанию ARC может вырасти довольно заметно. На VDS в 2–4 ГБ стоит ограничить верхнюю границу:
echo 'options zfs zfs_arc_max=536870912' | sudo tee /etc/modprobe.d/zfs.conf
sudo update-initramfs -u
sudo reboot
Здесь zfs_arc_max установлен на 512 МБ. Подберите значение под свой проект, мониторьте потребление памяти и метрики ZFS.
Включаем и проверяем сжатие lz4
lz4 — дефолтный и лучший компромисс для VDS: минимальная нагрузка на CPU и хороший выигрыш на текстовых и JSON/PHP‑файлах, дампах БД, логах. Включать удобно на уровне пула или конкретного датасета:
zfs set compression=lz4 zdata
zfs get compression zdata/project/www
zfs get compressratio zdata/project/www
Следите за compressratio: реальный коэффициент сжатия покажет, есть ли профит. На статику и бэкапы в tar.gz рассчитывать не стоит — уже сжаты.
Snapshots: стратегия именования и ретеншн
Снапшоты создаются мгновенно и занимают место только за счёт дельты изменений. Простейшее правило — делать частые локальные снапшоты и удалять старые по политике. Например, почасовые за последние 24 часа, дневные — за 7–14 дней, недельные — за 4–8 недель.
Имя снапшота должно быть машинно‑сортируемым: @YYYYMMDD-HHMM. Рекурсивный снапшот корневого датасета проекта:
SNAP=$(date -u +%Y%m%d-%H%M)
sudo zfs snapshot -r zdata/project@${SNAP}
zfs list -t snapshot -r zdata/project
Для автоматизации используйте systemd‑таймеры или cron. В systemd‑подходе удобно вынести логику в скрипт и вызывать таймером разной периодичности, сохраняя единый формат имён и политику ретенции.
Пример: systemd‑юниты для почасовых снапшотов
sudo tee /usr/local/sbin/zfs-snapshot-hourly > /dev/null << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
POOL_DATASET="zdata/project"
SNAP="$(date -u +%Y%m%d-%H%M)"
zfs snapshot -r "${POOL_DATASET}@${SNAP}"
# Удалить снапшоты старше 36 часов
zfs list -t snapshot -o name -s creation -r "${POOL_DATASET}" | grep "@" | head -n -24 | xargs -r -n 1 zfs destroy -r
EOF
sudo chmod +x /usr/local/sbin/zfs-snapshot-hourly
sudo tee /etc/systemd/system/zfs-snapshot-hourly.service > /dev/null << 'EOF'
[Unit]
Description=ZFS hourly snapshots
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/zfs-snapshot-hourly
EOF
sudo tee /etc/systemd/system/zfs-snapshot-hourly.timer > /dev/null << 'EOF'
[Unit]
Description=Run ZFS hourly snapshots
[Timer]
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now zfs-snapshot-hourly.timer
Политику удаления подберите под собственный объём и RPO. Для датасетов со стремительным приростом (логи, кеши) снапшоты можно отключать или жёстко ограничивать через квоты.
send/receive: как устроить инкрементальные бэкапы
Основная сила ZFS в бэкапах — потоковые операции send/receive. Базовая идея: первый раз отправляем полный снапшот, далее — только дельты между последовательными снапшотами.
Локальная репликация
Если у вас на сервере есть второй пул (например, другой диск), можно делать локальную резервную копию:
# Первый полный перенос
zfs send -R zdata/project@20250101-0100 | zfs receive -F backup/project
# Инкрементальный перенос
zfs send -R -I 20250101-0100 zdata/project@20250101-0200 | zfs receive -F backup/project
Ключ -R переносит вместе со снапшотом все дочерние датасеты и свойства. Ключ -I отправляет цепочку инкрементов от указанной точки до целевого снапшота.
Репликация по SSH на удалённый сервер
Принцип тот же, но поток уходит через SSH. Перед первой отправкой оцените объём:
# Оценка размера потока
zfs send -nP -R zdata/project@20250101-0100
# Полный бэкап по SSH (пример)
zfs send -R zdata/project@20250101-0100 | ssh user@backup-host zfs receive -F backup/project
# Инкремент
zfs send -R -I 20250101-0100 zdata/project@20250101-0200 | ssh user@backup-host zfs receive -F backup/project
Для нестабильных каналов используйте возобновляемую передачу: флаг -s у send и аналогичная поддержка у receive. Также можно вставить буферизатор потока между send и receive для сглаживания пульсаций сети.
Чтобы исключить случайное удаление ещё не реплицированного снапшота, ставьте hold на момент создания и снимайте после успешной доставки:
zfs hold keep zdata/project@20250101-0200
# ... репликация ...
zfs release keep zdata/project@20250101-0200

Восстановление: rollback, clone и выборочная отдача
Откат к снапшоту моментален, но уничтожает изменения «сверху» текущей версии датасета. Используйте аккуратно на боевых датасетах БД.
# Мгновенный откат всего датасета
zfs rollback -r zdata/project@20250101-0200
Безопаснее — поднять клон для проверки, переключить сервисы и затем принять решение:
zfs clone zdata/project@20250101-0200 zdata/project-verify
# смонтировать, проверить, затем удалить клон
zfs destroy zdata/project-verify
Квоты и свободное место: не загоняйте пул в 100%
Заполнять пул под завязку в ZFS — плохая идея: растёт фрагментация и деградирует производительность, операции могут начать ошибаться из‑за нехватки места под метаданные. Держите 10–20% свободного. Для шумных датасетов (логи, кеши) задавайте quota/refquota и чистите регулярно.
zfs set quota=5G zdata/project/logs
zfs set refquota=2G zdata/project/www
zfs list -o name,used,available,refer,referenced,quota,refquota -r zdata/project
Обслуживание: scrub, мониторинг и уведомления
Периодически запускайте zpool scrub для проверки целостности. На VDS с одним диском scrub всё равно имеет смысл: он обнаружит немые повреждения и позволит ZFS восстановить данные, если настроены дополнительные копии на уровне датасета.
sudo zpool scrub zdata
zpool status -x
zpool iostat -v 1
Настройте системные уведомления по событиям ZFS (zed) и интеграцию с вашей системой мониторинга: статус пула, свободное место, частота ошибок ввода‑вывода, длительность транзакционных групп.
Опции, которые часто спрашивают
- Сжатие gzip/zstd вместо lz4? zstd даёт больший коэффициент сжатия, но и выше CPU‑стоимость. На 1–2 vCPU VDS по умолчанию оставайтесь с lz4. Можно точечно включать zstd для архивных, редко изменяемых данных.
- Собственный SLOG (журнал) на VDS? На виртуалке дополнительный реально отдельный низколатентный диск под SLOG обычно недоступен. Разносить журнал на тот же пул бессмысленно; лучше положиться на стандартный ZIL и корректный
syncу приложений. - Encryption на уровне ZFS? Встроенное шифрование доступно и полезно, но учитывайте накладные расходы CPU и процедуру управления ключами. Тестируйте заранее.
- copies=2 на одном диске? Может помочь от битых блоков, но увеличит запись в 2 раза. На VDS чаще выгоднее регулярная send/receive‑репликация на удалённый узел.
Типичный рабочий конвейер Dev/Prod
У веб‑проектов удобный паттерн выглядит так: в продакшене раз в час делается рекурсивный снапшот корневого датасета проекта, тут же уходит инкремент на бэкап‑сервер. Для тестовой среды вы по запросу берёте свежий снапшот продакшена и получаете клон на staging без копирования данных. Для миграций — сначала полный send, затем короткие инкременты до окна переключения, после которого выполняете финальный инкремент и атомарный запуск на новом сервере.
ZFS не только про «быстро откатиться». Это про воспроизводимые миграции и бэкапы, где дельты считаются файловой системой, а не утилитами общего назначения.
Проверочный чек‑лист перед запуском в продакшен
- Пул создан с
ashift=12, включеныautotrim=on,atime=off,compression=lz4,xattr=sa. - Датасеты разделены по ролям:
www,db,logsи др.; на БД заданrecordsize8K/16K иlogbias=latency. - Ограничен ARC через
zfs_arc_maxдля экономии ОЗУ на слабых VDS. - Настроены почасовые/дневные snapshots и ретеншн; снапшоты именуются
@YYYYMMDD-HHMM. - Отлажен конвейер send/receive: полный первый бэкап и инкременты; есть hold‑марки до доставки.
- Критичные шумные датасеты имеют квоты; пул не заполняется свыше 80–90%.
- Раз в неделю/месяц запускается
zpool scrubи мониторятся алерты.
Отладка производительности
На симптом «медленно» смотрим метрики: задержки I/O (zpool iostat -v), утилизация CPU и процент кэш‑попаданий (ARC hit/miss в экспозиции ZFS). Если база часто читает одно и то же, увеличьте ARC в разумных пределах. При высоком проценте синхронных записей проверьте конфигурации БД: режим fsync, размеры журналов, паттерны чекпоинтов. За деталями по СУБД смотрите практикум по оптимизации в статье тюнинг PostgreSQL.
Вывод
ZFS отлично чувствует себя на VDS и решает задачи, которые раньше требовали сложной комбинации rsync+tar+mysqldump+скриптов. Снимки за секунды, инкрементальная репликация, честные бэкапы на уровне блоков и прозрачное сжатие lz4 — это реальная экономия и повышение надёжности. Начните с аккуратной разметки датасетов, включите lz4, автоматизируйте snapshots и send/receive — и у вас будет простой, воспроизводимый и быстрый процесс резервного копирования и миграций.


