Однажды на работе мне начальник поставил задачу создать резервную копию сервера телефонии Asterisk, чтобы в случае отказа сервер телефонии можно было поднять на виртуалке. Проблема оказалась, что Asterisk находится физически на сервере в Екатеринбурге и установлен на FreeBSD 13.1, а я нахожусь в Тюмени. Т. е. прийти в серверную сделать холодный backup не получится. Я пообщался с коллегами, они сказали: «Никакой проблемы нет, используй ZFS snapshots для резервного копирования».
Так я узнал о существовании файловой системы ZFS. Это файловая система, которая сама следит за целостностью данных, умеет экономить место и защищать файлы от потерь при сбоях. Её главная идея — надёжность и удобство в управлении большими объёмами данных.
Основные технологии ZFS:
- Copy-on-Write (COW) — вместо перезаписи данных создаются новые копии, старые остаются нетронутыми.
- Снапшоты (Snapshots) — быстрые «фотографии» состояния файловой системы в любой момент.
- Компрессия данных — автоматическое сжатие для экономии места.
- Дедупликация — удаление повторяющихся данных для оптимизации хранения.
- Интегрированное управление томами — управление дисками и пулами без внешних менеджеров типа LVM.
- Шифрование для защиты данных.
Любые Ваши фантазии для работы с жесткими дисками уже реализованы на уровне файловой системы.
Вот хорошее обзорное видео про эту файловую систему «ZFS — Лучшая! Файловая? Система»
Сначала для меня всё было покрыто магией. И было уйма вопросов. Начал разбираться, магии никакой нет.
- Почему быстро создаётся снапшот?
ZFS использует Copy-on-Write (COW), чтобы при изменении данных не перезаписывать их на месте, а записывать новую версию в новое место. Снапшот фиксирует указатели на блоки в момент времени — это мгновенная «точка сохранения», не дублирующая сами данные. Благодаря COW снапшоты не занимают лишнего места до изменений и мгновенно создаются. - А как происходит сжатие на уровне файловой системы?
ZFS поддерживает прозрачное сжатие данных на уровне блочной записи. При записи данных ZFS пытается сжать каждый блок с использованием выбранного алгоритма (lz4, gzip и др.). Если сжатый блок меньше исходного — сохраняется сжатый вариант, иначе — оригинал. Это уменьшает объём хранения, повышает скорость ввода-вывода (меньше данных читается с диска) и экономит место без вмешательства приложений. - А как происходит дедупликация?
Дедупликация в ZFS устраняет дублирующиеся блоки данных на уровне всей файловой системы. При записи нового блока ZFS вычисляет его хэш (обычно SHA-256) и проверяет, есть ли такой уже на диске. Если есть — сохраняется только ссылка, а не сам блок. Это экономит место, особенно при хранении похожих данных, но требует много оперативной памяти и ресурсов для хэш-таблиц.
Хорошее видео «Моя лекция о COW-файловых системах (ZFS, BTRFS)» про то, что происходит у ZFS «под капотом».
Но ZFS далеко не идеальна:
- Лицензия ZFS не позволяет добавлять модуль в ядро Linux напрямую. Необходимо немного потанцевать с «бубном».
- Требуется 64-битная операционная система и минимум 2 ГБ оперативной памяти. И чем больше памяти, тем лучше. На моём сервере Asterisk в пике может легко «сожрать» до 30Gb, в обычном режиме около 13Gb хватает при объёме дискового пула в 1Tb.
- Не рекомендуется использовать аппаратные RAID с ZFS. ZFS любит управлять дисками напрямую. Очень много «фишек» сжатие, шифрование будут недоступны.
- ZFS не любит недостаток свободного места на диске. Решение: создание дополнительного dataset для резервирования пространства. Резервируется около 5% для быстрого освобождения дискового пространства.
- Высокий порог вхождения. Во всех технологиях ZFS надо сидеть и разбираться.
Итак, как создать и передать снапшот всей файловой системы Asterisk на удалённый сервер.
# Создание снапшота
zfs snapshot zfspool@today
# Передача снапшота по SSH на удалённый сервер
zfs send zfspool/data@today | root@192.168.0.2 zfs receive -F -v zfspool
На удалённом сервере
# Проверка после передачи
zfs list -t snapshot
# Смонтировать
mkdir -p /mnt/zfsrmount
mount -t zfs -o ro zfspool@today /mnt/zfsmount
Ура! Мы осуществили резервное копирование сервера, все могут расходится. Но не всё так просто. Возникли две проблемы:
- На удалённом сервере файловая система ext4, которая даже не подозревает о существовании ZFS.
- Как автоматизировать создание и пересылку снапшотов?
Но нет ничего невозможного для человека с интеллектом.
Как принять снапшот?
Что принять снапшот на удалённом сервере тоже должна быть ZFS, ext4 не подходит. Нет, впихнуть невпихуемое, конечно, можно. Только сил, ресурса и душевных мук это потребует неоправданно. Я пошёл более простым путём, создал виртуалку Debian 12 с ZFS. Но опять не всё так просто, в Linux ZFS как бы есть, но там какая-то дивная чехарда с лицензиями. Она не достаточно свободная, поэтому в официальную поставку Linux-дистрибутивов её не включают (кроме Ubuntu), и надо ставить вручную. Но есть хорошая инструкция «Debian Bookworm Root on ZFS» https://openzfs.github.io/openzfs-docs/Getting%20Started/Debian/Debian%20Bookworm%20Root%20on%20ZFS.html. Если вкратце, надо загрузится с LiveCD, разметить диск, установить загрузчик, скопировать операционку и провести её настройки из chroot.
Как автоматизировать пересылку снапшотов?
Всё, что может быть автоматизировано, должно быть автоматизировано. Есть программа Zrepl https://zrepl.github.io/ Она не только их создаёт и передаёт по расписанию, но и очищает старые.
На FreeBSD (asterisk) был создан следующий конфиг
global:
logging:
- type: "stdout"
level: "error"
format: "human"
- type: "syslog"
level: "warn"
format: "logfmt"
jobs:
- name: snapshots
type: snap
filesystems:
'<': true
snapshotting:
type: cron
prefix: zrepl_
cron: "0 0 * * *"
pruning:
keep:
- type: regex
negate: true
regex: '^zrepl_'
- type: grid
grid: 24x1h(keep=all) | 60x1d
regex: '^zrepl_'
- name: target_nas
type: source
serve:
type: tcp
listen: "192.168.0.1:8888"
listen_freebind: true
clients: {
"10.72.3.110" : "aster-backup"
}
filesystems: {
"<": true,
}
snapshotting:
type: manual
На FreeBSD есть 2 задания:
- snapshots: ежедневно в полночь по cron делает ZFS-снимки всех файловых систем с префиксом
zrepl_
, хранит часовые за последние 24 ч и по одному за каждый из предыдущих 60 дней, удаляя более старые снимки по сеточной политике. - target_nas: запускает TCP-сервер на 192.168.0.1:8888 для клиента 10.72.3.110 (
aster-backup
), выставляет все файловые системы и ждёт ручного создания снимков (auto-snapshots отключены).
А на Debian 12 (aster-backup)
global:
logging:
- type: "stdout"
level: "error"
format: "human"
- type: syslog
format: human
level: "warn"
jobs:
- name: pull_aster
type: pull
connect:
type: tcp
address: "192.168.0.1:8888"
root_fs: rpool/backups
interval: 1h
recv:
placeholder:
encryption: off
properties:
inherit:
- mountpoint
- canmount
conflict_resolution:
initial_replication: all
pruning:
keep_sender:
- type: regex
regex: '.*'
keep_receiver:
- type: regex
negate: true
regex: '^zrepl_'
- type: grid
grid: 1x1h(keep=all) | 12x1h | 60x1d | 3x30d
regex: '^zrepl_'
Задание pull_aster: каждый час тянет снимки по TCP с 192.168.0.1:8888 в /rpool/backups
, приём без шифрования, при конфликте забирает всё с источника, при очистке на отправителе хранит всё, на приёмнике удаляет всё, что не начинается с zrepl_
, и для своих zrepl_
-снимков держит 1×1ч, затем 12×1ч, 60×1д и 3×30д.
Почему используются задания pull, а не push?
Из-за централизованного управления. Расписание бэкапов задаётся только на стороне «сервер-бэкапа» — не нужно настраивать cron на каждом клиенте и следить за тем, что они вовремя завершили push. Задания pull могут становиться в очередь.
Запускаем получение снапшота с удалённого сервера командой:
zrepl signal wakeup pull_aster
И ждём, у меня получение первого снапшота размером 500Gb при ширине канала 100Mb/s заняло около 10 часов. Следующие инкрементальные в разы быстрее, они объёмом 80-100Mb.
За основу этой схемы резервного копирования было взято видео «ZFS как архитектурное решение для резервного копирования хостинга».
Для zrepl есть ряд полезных команд.
#проверить статус zrepl
zrepl status
#проверить конфиг zrepl
zrepl configcheck
# перезапустить zrepl на FreeBSD
systemctl restart zrepl
#просмотр журнала на Debain
journalctl -u zrepl.service
journalctl -u zrepl.service -n 40
#наблюдать за файлом журнала
journalctl -fu zrepl
#просмотр списка снапшотов
zfs list -t snapshot
#удаление снапшота, если что-то пошло не так
zfs destroy -r rpool/backups/zfspool/var/log
#если снапшот не удаляется, надо определить кто его "держит" и освободить.
zfs holds rpool/backups/zfspool/var/log@zrepl_20250512_110640_000 zfs release zrepl_last_received_J_pull_aster rpool/backups/zfspool/var/log@zrepl_20250512_110640_000
#посмотреть свойства датасета
zfs get all rpool/backups
#удалить созданное дерево
zfs destroy -rf rpool/backups/zfspool
Теперь автоматизация резервного копирования настроена, снапшоты стабильно передаются на удалённый сервер, хранятся по расписанию и очищаются без моего вмешательства. Но на этом работа не заканчивается. Важно не просто делать бэкапы, а проверять, можно ли из них восстановить рабочую систему. Без этой проверки вся схема — иллюзия безопасности. В следующей статье https://infoblog72.ru/blog/kak-vosstanovit-asterisk-iz-snapshota-poshagovaya-instrukcziya.html расскажу, как из снапшота развернуть полноценную копию сервера Asterisk на виртуальной машине.