MAATRIX / Блог / Снапшоты ZFS против бэкапа: в чём разница и что не спасёт

Снапшоты ZFS против бэкапа: в чём разница и что не спасёт

MAATRIX

zfs snapshot выполняется меньше секунды и не просит подтверждения — не удивительно, что после нескольких удачных откатов у администратора складывается ощущение «у меня всё под снапшотами, бэкап можно не настраивать». Ощущение обманчиво: снапшот ZFS — превосходный инструмент для быстрого локального отката, но он физически живёт там же, где и данные, и это делает его бесполезным ровно в тех сценариях, ради которых вообще нужен бэкап.

Как устроен снапшот ZFS изнутри

ZFS — файловая система с архитектурой copy-on-write (COW): она никогда не перезаписывает блок данных на диске. Когда файл меняется, новые данные пишутся в свободное место пула, а указатели дерева метаданных пересчитываются так, чтобы вести к новым блокам. Старый блок при этом никуда не девается — он просто становится «сиротой» и попадает в список свободного места, если на него больше никто не ссылается.

Снапшот в этой картине — это не копия данных, а замороженный набор указателей на то состояние дерева блоков, которое было на момент его создания. Команда:

zfs snapshot pool/data@before-update

не копирует ни байта. Она фиксирует текущие указатели файловой системы pool/data под именем before-update и говорит пулу: «эти блоки не трогать, даже когда файловая система перестанет на них ссылаться». Именно поэтому создание снапшота занимает миллисекунды независимо от того, лежит в датасете 10 ГБ или 10 ТБ — размер данных не имеет значения, потому что копируются не данные, а ссылки на них.

Проверить, что снапшот только что созданный и не старый, можно так:

zfs list -t snapshot -o name,creation,used,referenced pool/data

Сразу после создания в столбце USED для свежего снапшота будет стоять 0 (или несколько килобайт метаданных) — это ожидаемо и подтверждает механику: снапшот не занимает места сам по себе.

Почему место начинает расходоваться только при изменении данных

Место под снапшотом растёт не в момент его создания, а в момент, когда исходная файловая система пытается изменить или удалить блок, на который снапшот всё ещё ссылается. Из-за COW новый блок пишется в новое место, а старый блок не освобождается — он остаётся жив, потому что на него смотрит снапшот. Формально это называется «удержание блока» (block retention): пока жив хотя бы один снапшот, ссылающийся на блок, этот блок нельзя вернуть в пул свободного места, даже если актуальная файловая система его больше не видит.

Отсюда практическое следствие: объём, который «весит» снапшот, — это не размер датасета на момент создания, а объём данных, изменившихся *после* создания снапшота. Датасет, который не менялся неделю, будет держать недельной давности снапшот практически бесплатно. Тот же датасет с активной базой данных, где каждую минуту переписываются одни и те же страницы таблиц, будет раздувать снапшот на гигабайты в час — потому что COW создаёт новую версию блока при каждой правке, а старая версия остаётся живой ради снапшота.

Посмотреть, сколько места держат именно снапшоты (а не текущие данные), можно так:

zfs list -o name,used,usedbydataset,usedbysnapshots,usedbychildren pool/data

Поле usedbysnapshots — это ровно то место, которое вы вернёте, удалив все снапшоты датасета. Если оно растёт быстрее, чем вы ожидали, — это сигнал, что данные меняются активнее, чем кажется, или что снапшоты копятся дольше, чем нужно (типичная причина — забытое задание zfs-auto-snapshot без ротации).

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Что снапшот ZFS реально решает — и решает хорошо

Есть класс задач, для которых снапшот ZFS — правильный и достаточный инструмент, и не нужно тянуть сюда полноценный бэкап:

  • Откат неудачного обновления. Сняли снапшот перед apt upgrade или обновлением конфигурации, обновление сломало сервис — откатились командой zfs rollback pool/data@before-update за секунды, без развёртывания архива.
  • Быстрая проверка «а что если». Тестируете миграцию схемы БД, рискованный скрипт или ручное вмешательство в данные — снапшот даёт путь назад без даунтайма на восстановление.
  • Замеченная сразу ошибка администратора. Случайно удалили не ту директорию рабочей веткой скрипта пять минут назад, снапшот с утра ещё жив — файл можно вытащить прямо из скрытой директории:
ls /pool/data/.zfs/snapshot/before-update/
cp /pool/data/.zfs/snapshot/before-update/important.conf /pool/data/important.conf

Все эти сценарии объединяет одно: снапшот работает, пока и данные, и он сам физически доступны на одном и том же пуле. Как только эта предпосылка нарушается — снапшот бессилен, и дальше речь именно об этом.

Общая судьба: снапшот и данные лежат на одном пуле

Снапшот ZFS не выносит копию за пределы пула — он существует как часть того же самого дерева метаданных, на тех же дисках, в том же zpool. Это прямая аналогия с давно разобранным мифом «RAID — это бэкап»: избыточность и мгновенные точки отката защищают от одного класса отказов и абсолютно бессильны против другого — отказа самого носителя данных как единого целого.

Конкретные сценарии, где снапшот погибает вместе с данными:

СобытиеЧто происходит с даннымиЧто происходит со снапшотами
Отказ одного диска в RAID-Z1/Z2 в пределах резерваДанные доступны, идёт resilverСнапшоты не пострадали
Отказ дисков сверх избыточности RAID-Z (например, 2 диска в RAIDZ1)Пул деградирует или разваливаетсяСнапшоты теряются вместе с пулом
Повреждение метаданных пула (битый uberblock, битая память при отсутствии ECC)Пул может не импортироватьсяСнапшоты недоступны так же, как и данные
Кража или физическое уничтожение сервераДанные потеряныСнапшоты потеряны вместе с диском
Шифровальщик с правами root на хостеДанные зашифрованыЗлоумышленник с root может удалить и снапшоты (zfs destroy)

Последняя строка стоит отдельного внимания: снапшот ZFS по умолчанию не защищён от удаления тем же пользователем, у которого есть права на запись в пул. Если атакующий получил root на сервере, команда zfs destroy pool/data@before-update уничтожает снапшот так же легко, как обычный файл. Частичная защита — свойство hold:

zfs hold keep pool/data@before-update

Оно блокирует удаление конкретного снапшота даже командой destroy без явного zfs release, но не спасает от уничтожения всего пула целиком и не защищает от zpool destroy с более высокими правами.

Логическая порча данных: снапшот спасает только «до», а не «после»

Второй класс задач, где снапшот интуитивно кажется бэкапом, — это защита от логической порчи: случайное удаление важного файла, баг в приложении, который затирает не те строки в базе, шифровальщик внутри виртуальной машины. Здесь снапшот действительно может спасти — но только при выполнении двух условий одновременно:

  1. Снапшот был создан до момента порчи данных.
  2. Снапшот ещё не удалён ротацией на момент, когда порчу заметили.

Оба условия звучат очевидно, но именно на них ломаются реальные инциденты. Типичная ротация снапшотов через zfs-auto-snapshot или cron-скрипт держит, скажем, снапшоты за последние 24 часа почасово и за последние 30 дней ежедневно. Если шифровальщик или неисправный скрипт медленно портит данные в фоне (что для современных шифровальщиков с задержкой активации — не редкость), к моменту обнаружения проблемы «чистого» снапшота может просто не остаться в хранимом окне.

Ещё более прямая проблема: снапшот на том же пуле не защищает от сценария, где повреждение задевает сам пул, а не только логическое содержимое датасета — например, битый диск с необнаруженными ошибками до момента, пока checksum ZFS не поймает несовпадение при чтении. Снапшот в этом случае показывает ту же порчу, что и текущие данные, потому что физически это один и тот же набор дисков.

Как превратить локальный снапшот в реальную резервную копию

Единственный способ получить от снапшот-механики ZFS полноценную защиту, а не просто быстрый локальный чекпоинт, — вынести копию снапшота за пределы исходного пула, на другое физическое устройство или другой сервер. Штатный механизм для этого — zfs send / zfs receive: он сериализует содержимое снапшота (а при инкрементальной отправке — только разницу между двумя снапшотами) в поток, который можно передать на другой пул, в том числе по сети через SSH:

zfs send pool/data@before-update | ssh backup-host zfs receive backup-pool/data-copy

После такой передачи на удалённом сервере лежит независимая копия данных, которая переживёт отказ исходного пула, потерю сервера и любые действия злоумышленника, получившего доступ только к исходной машине. Это принципиально иной уровень защиты по сравнению с локальным zfs snapshot, и подробный разбор механики инкрементальной отправки, тонкостей -i/-I и типичных грабель с zfs receive -F — тема отдельного материала, здесь важно зафиксировать сам принцип: снапшот становится бэкапом только в момент, когда его копия покидает исходный пул.

Отдельно стоит учитывать, что репликация снапшота — это не то же самое, что резервное копирование прикладного уровня (дампы БД, архивы файлов с версионированием, инкрементальные бэкапы через отдельные системы). ZFS-репликация копирует блоки файловой системы как есть, включая уже случившуюся логическую порчу, если она попала в реплицируемый снапшот. Если приложение записало битые данные и это зафиксировано снапшотом до того, как порчу заметили, репликация добросовестно унесёт битые данные на второй сервер тоже. Поэтому на практике снапшот-репликация ZFS хорошо дополняет, но не заменяет прикладной бэкап (дампы БД, экспорт конфигураций) — они защищают от разных типов проблем и обычно нужны оба.

Практические правила: сколько хранить и на что смотреть

Несколько ориентиров для настройки снапшотов ZFS так, чтобы они реально помогали, а не просто копили место:

  • Разделяйте частоту и глубину хранения. Частые снапшоты (каждые 15–60 минут) полезны для отката недавних ошибок, но их не нужно хранить неделями — держите короткое окно (например, 24–48 часов) и переходите на ежедневные/еженедельные для более длинной истории.
  • Мониторьте usedbysnapshots, а не только общее занятое место. Резкий рост этого параметра — сигнал либо аномальной активности записи, либо забытой ротации.
  • Ставьте hold на снапшот перед рискованной операцией, если планируете откатиться именно на него, а не полагаетесь на автоматическую ротацию, которая может успеть его удалить.
  • Не путайте снапшот с квотой и резервом. Свойство refreservation резервирует место под сам датасет и не имеет отношения к снапшотам; при планировании места под растущие снапшоты закладывайте отдельный запас в пуле — переполненный пул ZFS деградирует по производительности задолго до 100% заполнения.
  • Настройте репликацию снапшотов на второй пул/сервер как минимум для данных, потеря которых недопустима — это единственная часть схемы, которая переживает отказ исходного железа.
  • Проверяйте восстановление, а не только факт создания снапшота. Снапшот, который никогда не пробовали откатывать или реплицировать, — это непроверенная гипотеза о защите, а не защита.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Снапшот ZFS замедляет работу пула?

Сам факт существования снапшота почти не влияет на производительность записи — COW-механика работает так же, независимо от наличия снапшотов. Но чем больше живых снапшотов и чем сильнее фрагментировано свободное место из-за удержания старых блоков, тем выше может быть нагрузка на аллокатор при поиске свободных блоков под запись.

Можно ли смонтировать снапшот и посмотреть файлы, не откатываясь?

Да, через скрытую директорию .zfs/snapshot/<имя>/ внутри датасета (по умолчанию видна, если не отключено свойство snapdir) — можно копировать отдельные файлы без полного zfs rollback.

Что будет, если удалить снапшот, на который есть zfs clone?

Пока у снапшота есть хотя бы один клон, ZFS не даст его удалить обычной командой — сначала нужно либо promote клон, либо удалить сам клон.

Снапшот ZFS и бэкап на уровне гипервизора (например, снапшот виртуалки в Proxmox) — это одно и то же?

Нет, хотя принцип COW похож. Снапшот ZFS работает на уровне файловой системы/пула ниже гипервизора, а снапшот виртуальной машины — на уровне диска ВМ; про механику снапшотов виртуализации отдельно можно почитать в разборе того, как устроены снапшоты в Proxmox — логика похожа, но уровень другой, и путать их не стоит.

Сколько снапшотов ZFS можно держать без проблем?

Технического жёсткого лимита нет, но чем длиннее цепочка снапшотов, тем дольше выполняются операции удаления старых снапшотов (нужно пересчитать, какие блоки уже никому не нужны) — на практике сотни снапшотов на активном датасете уже заметно замедляют zfs destroy и zfs list.

Нужен ли снапшот ZFS, если уже настроен внешний бэкап через borgbackup или похожий инструмент?

Да, это разные слои защиты: прикладной бэкап вроде borgbackup обычно снимается реже (часы, а не минуты) и хранится дольше, а снапшот ZFS даёт мгновенный локальный откат на недавнее состояние без ожидания восстановления из архива.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →