Программисты уже давно стараются использовать серьёзные production-ready решения для сохранения личных данных. Требования к инструментам растут, и если когда-то было принято держать домашние файлы на NAS и перекачивать снапшоты сервера через Rsync, то сейчас на передовой гораздо более сложные и функциональные проекты. Один из них — возможно, самый перспективный и мощный — файловая система ZFS. Оставив конкурента (btrfs) далеко позади и отстояв право на опен-сорс, она активно применяется как в хайлоаде, так и в личных системах хранения. Далее мы разберём её основные аспекты и за несколько минут поднимем рабочую систему бэкапа на удалённой VPSке. Поехали!
Кратко о ZFS
В ZFS заложена одна простая идея: должна существовать единая файловая система, заточенная под идеальное локальное хранение данных. Без лишних слоёв над LVM, без жёсткой привязки к железу, с максимальным покрытием задач прямо из коробки. И список возможностей у неё впечатляющий, вот самые базовые:
- Copy-on-write: данные никогда не перезаписываются, все старые версии доступны напрямую с диска, без необходимости использовать write-ahead log (и как следствие, сверять журналы). ZFS работает на дереве хэшей (Merkle tree), гарантирующее консистентность в обмен на затратные вычисления всего дерева. Таким образом, система прежде всего нацелена на максимальную сохранность всех данных.
- Так как любое сохранение состояния выполняется через атомарные транзакции, доступны «мгновенные снапшоты», которые действительно можно снимать с почти неограниченной частотой благодаря фиксированной стоимости. Не нужно проверять изменения всех данных, достаточно оперировать хэшами, за валидацию которых отвечает корневой блок дерева.
- Программный RAID через mirror или raidz — аналог RAID 5/6/7 — конфигурируется через виртуальные устройства (vdev). Нет зависимости от конкретного железа (не придётся бояться write-hole), можно выбрать между надёжностью и производительностью на одном и том же наборе дисков. А ещё при избыточности ZFS автоматически выполняет self-healing при случайных ошибках.
- Потоковое сжатие (LZ4/gzip) работает из коробки, не накладывая заметной задержки при записи. При этом слегка возрастающий расход процессорного времени компенсируется меньшей нагрузкой на диск, что полезно и для отказоустойчивости, и для вариативности в выборе дисков.
- Категория «прочее»: дедупликация данных (отключаемая), независимые вложенные файловые системы со своими настройками, недостижимый лимит на размер файлов (ZFS 128-битная), и самое главное для нас: встроенный трансфер снапшотов через команды send/receive с триггерами before и after.
Здесь,
здесь и
здесь можно почитать подробнее про внутреннее устройство ZFS, её историю и нюансы администрирования.
Если сравнивать возможности Rsync и кастомных скриптов для синхронизации с ZFS, у них не будет ни шанса. Комбинируем плюсы выше: инкрементальные консистентные бэкапы + мгновенные снапшоты + программный RAID + отправка бэкапов из коробки = идеальный инструмент, объединяющий в себе мощный функционал и огромную производительность. Чтобы добиться подобного привычным инструментарием, понадобится оркестрировать кучу сервисов с многочисленными точками отказа.
Настраиваем бэкап за чашкой кофе
Разнообразие возможных хост-систем огромно — ZFS поддерживается на FreeBSD, Linux, Windows и MacOS, и разобрать все возможные сценарии в рамках одной статьи невозможно, поэтому рассмотрим самый расхожий вариант. Дано: локальная машина или сервер на Ubuntu/CentOS с данными (скажем, веб или база данных), которые необходимо сохранить на удалённый сервер (VPS на тех же системах), с версионированием и быстрым откатом.
Важный момент: за рокетсайнс под капотом ZFS расплачивается высокими требованиями к ресурсам при использовании raidz на обычных SSD (и при больших объёмах хранения, само собой). Поэтому для комфортной работы и на хост-машине, и на VPS потребуется как минимум двухъядерный процессор с 4гб памяти.
В последних версиях Ubuntu:
sudo apt install -y zfs
В версиях до 20.04:
sudo apt-get install zfsutils-linux
CentOS 8
sudo dnf install https://zfsonlinux.org/epel/zfs-release.el8_3.noarch.rpm
gpg --import --import-options show-only /etc/pki/rpm-gpg/RPM-GPG-KEY-zfsonlinux
# в большинстве случаем также потребуется DKMS:
sudo dnf install epel-release
sudo dnf install kernel-devel zfs
Команда zfs без переданных аргументов откроет help:
missing command
usage: zfs command args ...
where 'command' is one of the following:
version
create [-p] [-o property=value] ... <filesystem>
create [-ps] [-b blocksize] [-o property=value] ... -V <size> <volume>
destroy [-fnpRrv] <filesystem|volume>
destroy [-dnpRrv] <filesystem|volume>@<snap>[%<snap>][,...]
destroy <filesystem|volume>#<bookmark>
snapshot [-r] [-o property=value] ... <filesystem|volume>@<snap> ...
rollback [-rRf] <snapshot>
clone [-p] [-o property=value] ... <snapshot> <filesystem|volume>
Создадим пулы на хосте и на сервере командой zpool:
zpool create rpool
zpool create hotspare mirror sda sdb
Создадим в пулах файловые системы:
zfs create rpool/send-remote
zfs create hotspare/receive-remote
Запишем тестовый файл и создадим снапшот:
touch /rpool/send-remote/tmp
zfs snapshot rpool/send-remote@test0
Как видно, сохранение не заняло и секунды.
Теперь реплицируем данные на сервер (предполагается, что авторизация в ssh по ключу настроена, о том как это сделать, можно прочитать здесь):
zfs send -R rpool/send-remote@test0 | ssh my-vps-host zfs receive -A hotspare/receive-remote
Теперь у нас есть реплика данных хоста. Обновим данные на хосте:
echo 123 > /rpool/send-remote/tmp
zfs snapshot rpool/send-remote@test1
Теперь нам не нужно делать можную реплику, достаточно инкрементальной записи:
zfs send -i rpool/send-remote@test1 | ssh my-vps-host zfs receive -A hotspare/receive-remote
Готово! Данные сохраняются на сервере, остаётся только настроить отправку по вашим триггерам (и/или регулярную синхронизацию). Для этого есть много готовых скриптов (пример), но лучше разобраться и написать свой, используя документацию
Заключение
Полностью разобраться в ZFS — огромный труд, освоив который, можно смело идти админить кровавый энтерпрайз. Но не всегда нужно идти на такие жертвы, достаточно изучить базовый функционал и написать пару скриптов, чтобы добиться результата, который потребовал бы куда более неудобного управления цепочкой более простых, но узкоспециализированных инструментов.