Сколько снапшотов можно держать: цена каждого следующего в IOPS и в месте
«Снапшот перед изменением» — привычка, которая выглядит бесплатной страховкой: создал за секунду, откатился при проблеме, удалил. На практике так живёт один снапшот. А когда их накапливается пять, десять, двадцать — том незаметно теряет IOPS на записи, место кончается быстрее, чем кажется по логике «один снапшот — одна копия», а удаление старых снапшотов само по себе начинает грузить диск. Разберём механику copy-on-write, из чего складывается цена каждого следующего снапшота и сколько их реально имеет смысл держать.
Содержание
- Что происходит при снапшоте на уровне блоков
- Почему второй снапшот дороже первого
- Как замерить оверхед у себя, а не полагаться на чужие цифры
- Место: не копия целиком, а расхождение с оригиналом
- Время создания и удаления растёт вместе с количеством снапшотов
- Сколько снапшотов реально держать
- Когда снапшоты стоит заменить полным бэкапом
Что происходит при снапшоте на уровне блоков
Здесь важно различать два принципиально разных механизма, которые снаружи выглядят одинаково.
Classic COW (LVM dm-snapshot, старые снапшоты гипервизоров, часть облачных реализаций). Сам исходный том как был, так и остаётся обычным блочным устройством, данные пишутся поверх старых блоков. Снапшот — это отдельная область (exception store), куда перед первой перезаписью каждого блока копируется его старое содержимое. Именно поэтому первая запись в блок после создания снапшота — не одна операция, а фактически три: прочитать старый блок, записать его в область снапшота, записать новые данные в оригинал. Пока блок не тронут повторно — он с копией снапшота, второй раз этот блок уже не копируется, дальнейшие записи в него идут без дополнительного шага. Подробно эта механика на примере qcow2 разобрана в статье про copy-on-write и почему снапшот сначала бесплатный, а потом тормозит — там же видно, почему деградация нарастает не сразу, а по мере расхождения данных.
Copy-on-write на уровне файловой системы (ZFS, Btrfs, тонкие LVM-пулы). Здесь запись *никогда* не идёт поверх старого блока — новые данные всегда пишутся в свободное место, а указатели дерева блоков переключаются на новую версию. Снапшот в такой системе — это просто «замороженный» набор указателей на состояние дерева на момент создания, без копирования данных. Создание снапшота — метаданная операция, почти мгновенная и не зависящая от размера тома. Цена здесь не в дополнительной записи при каждой операции ввода-вывода, а в другом: старые блоки, на которые ссылается снапшот, нельзя освободить, пока жив снапшот. Оверхед смещается из write-пути в занятое место и в операции сборки мусора.
Отсюда практический вывод: если вы видите деградацию IOPS сразу после появления снапшота — это почти наверняка classic COW (LVM, старые гипервизорные снапшоты). Если IOPS на запись не изменился, а начал расти только занимаемый объём — это ZFS/Btrfs-подобная модель.
Почему второй снапшот дороже первого
На classic COW цена растёт не линейно в теории, а на практике довольно близко к линейной по числу *одновременно живых* снапшотов одного origin-тома. Причина простая: у каждого снапшота своя область exception store, и при первой перезаписи блока после создания снапшота старое содержимое нужно скопировать в *каждый* снапшот, который ещё не имеет своей копии этого блока. Один живой снапшот — одна дополнительная копия на «первую» запись в блок. Пять живых снапшотов, взятых в разное время, — потенциально до пяти дополнительных копий на тот же блок, если каждый снапшот успел зафиксировать блок в своём отличном от других состоянии.
LVM thin-пул смягчает картину: снапшоты в тонком пуле разделяют общее адресное пространство и B-tree метаданных, поэтому запись не мультиплицируется настолько прямолинейно, как в классическом dm-snapshot. Но и тут не бесплатно — каждая запись проходит через дополнительный уровень поиска и аллокации в разделяемых метаданных пула, и с ростом числа снапшотов эта B-tree становится глубже и медленнее обходится. Как это устроено и где начинаются реальные риски — в статье про LVM-снапшоты, расширение и типовые ошибки.
В ZFS создание десятого снапшота само по себе не делает запись медленнее, чем при одном снапшоте, — операция всё так же O(1) по метаданным. Но растёт другое: zfs list -o space начинает показывать больше уникально удерживаемых снапшотами блоков, глубже становится дерево ссылок, а операции zfs destroy и zfs list над большим числом снапшотов требуют больше времени на обход бухгалтерии — это не то же самое, что просадка IOPS на запись, но тоже реальная цена, которую платит система при большом количестве накопленных снапшотов.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверКак замерить оверхед у себя, а не полагаться на чужие цифры
Готовых цифр вида «минус N% IOPS на снапшот» в этой статье не будет намеренно: реальная просадка зависит от типа хранилища (NVMe локально или сетевой блочный диск), профиля нагрузки (мелкая случайная запись бьёт по COW сильнее всего, последовательная крупная — почти не бьёт) и от того, сколько блоков реально успевает разойтись с оригиналом. Единственный надёжный способ — измерить на своей связке диска и гипервизора.
Практическая методика:
- Прогнать базовый профиль записи на чистом томе без снапшотов и зафиксировать результат:
fio --name=randwrite --filename=/dev/vgdata/lvtest \
--rw=randwrite --bs=4k --iodepth=32 --direct=1 \
--runtime=60 --time_based --group_reporting
- Создать один снапшот, повторить тот же fio-профиль на том же томе, сравнить IOPS и latency.
- Добавлять снапшоты по одному (например, до 3-5 живых), повторяя тест на каждом шаге — так видна форма кривой деградации, а не одна точка.
- Параллельно с тестом смотреть
iostat -x 1— колонки%util,w_await,avgqu-szпокажут рост очереди и задержки записи ещё до того, как это станет заметно приложению. - Для classic LVM — следить за состоянием области снапшота:
dmsetup status vgdata-lvtest-realиlvs -a -o +snap_percentпокажут, сколько exception store уже занято. - Для ZFS —
zpool iostat -v 1для операций на уровне пула иzfs list -o spaceдля распределения занятого места междуUSEDBYSNAPиUSEDDS.
Важно тестировать именно тем профилем ввода-вывода, который у вас реально есть в проде (случайная запись мелкими блоками для БД, последовательная — для логов и бэкапов), потому что чувствительность к COW-оверхеду у этих профилей отличается в разы.
Место: не копия целиком, а расхождение с оригиналом
Частая ошибка в планировании — считать, что снапшот сразу «весит» как весь том. На деле в момент создания снапшот почти ничего не занимает (метаданные плюс небольшая структура), а растёт по мере того, как оригинал расходится с зафиксированным состоянием. У classic COW это буквально объём уникальных блоков, перезаписанных на origin с момента создания снапшота. У ZFS — объём блоков, которые ещё нужны снапшоту, но уже никому больше (колонка USEDBYSNAP в zfs list -o space).
Отсюда следует контринтуитивный, но важный вывод: возраст снапшота сам по себе не определяет его размер — определяет объём перезаписанных данных за время его жизни. Снапшот базы данных с активной записью, простоявший сутки, может занять сопоставимо с половиной тома, если за эти сутки прошло много обновлений строк. А снапшот архивного, почти не меняющегося тома может прожить месяцы и остаться почти пустым.
Практический риск для classic LVM и тонких пулов — переполнение области снапшота или самого thin-пула. В классической схеме переполнившийся снапшот просто становится невалидным (инвалидируется, откат по нему уже невозможен) — без предупреждения, если не настроен мониторинг. В тонком пуле последствия жёстче: если места в пуле не хватает, под угрозой может оказаться запись *во все* тома пула, а не только в переполнившийся снапшот — том может уйти в приостановку записи (suspend) до вмешательства администратора. Именно поэтому мониторинг %data пула и snap_percent снапшотов — не опция, а обязательная часть эксплуатации, что подробнее разбирается в той же статье про LVM-снапшоты и риски переполнения.
Время создания и удаления растёт вместе с количеством снапшотов
Создание одного снапшота почти всегда быстро — это метаданная операция что в LVM (аллокация exception table), что в ZFS/Btrfs (переключение указателей дерева), и время создания практически не зависит от размера тома. А вот удаление — совсем другая история, и именно здесь чаще всего прилетает неожиданная нагрузка.
В classic LVM удаление отдельного снапшота из цепочки требует объединения (merge) его exception-таблицы с состоянием origin либо просто освобождения области — операция сама по себе не тяжёлая, но если удаляете сразу несколько накопившихся снапшотов, суммарная нагрузка на диск в моменте заметна.
В ZFS удаление одного снапшота (zfs destroy pool/dataset@snap) обычно быстрая метаданная операция, но если снапшот удерживал много уникальных блоков (был живым во время активной записи), система должна их освободить — это порождает всплеск операций записи метаданных и может проявиться как временная задержка на пуле. Удаление сразу пачки старых снапшотов одной командой (zfs destroy pool/dataset@snap1,snap2,snap3) объединяет освобождение в одну транзакцию — быстрее с точки зрения общего времени, но всплеск нагрузки в моменте выше. На проде такие массовые удаления имеет смысл выполнять в окно с низкой нагрузкой, а не как попало посреди рабочего дня.
Облачные снапшоты обычно устроены как инкрементальные цепочки на стороне провайдера: удаление снапшота из середины цепочки может потребовать консолидации дельт в соседний снапшот на backend-стороне. Формально это асинхронная операция и с виду «бесплатная» для вас, но конкретный механизм и то, влияет ли она на производительность тома во время консолидации, зависит от провайдера — стоит свериться с документацией конкретной платформы, а не считать это универсально нейтральной операцией.
Сколько снапшотов реально держать
Единой правильной цифры нет — она зависит от механизма (classic COW против CoW-файловой системы), интенсивности записи и запаса по месту. Но есть рабочие ориентиры, от которых можно оттолкнуться.
Для classic LVM и других систем с прямым write-penalty на снапшот:
- Держите минимально возможное число живых снапшотов — в идеале один, редко больше двух-трёх одновременно.
- Снапшот перед рискованной операцией (миграция, обновление, ручное изменение схемы БД) должен жить часы, а не недели — удаляйте его сразу после подтверждения, что всё в порядке.
- Не используйте снапшот как замену бэкапа с длинным сроком хранения — цена в IOPS будет расти всё время его жизни.
Для ZFS, Btrfs и тонких пулов (нет write-penalty, но есть накопление места и метаданных):
- Можно держать заметно больше — условно говоря, порядка десятков снапшотов, если позволяет запас места и мониторинг настроен заранее.
- Ориентируйтесь на классическую GFS-схему (grandfather-father-son) как стартовый шаблон, а не догму: например, почасовые снапшоты за последние 24-48 часов, ежедневные за неделю, еженедельные за месяц, ежемесячные — единицы штук для долгого архива. Конкретные числа подгоняйте под реальную скорость роста
USEDBYSNAPна вашем датасете. - Для высоконагруженных на запись томов (БД с активным OLTP) даже в ZFS не стоит копить длинную историю снапшотов — рост занятого места будет непропорционально быстрым из-за постоянной перезаписи блоков.
Ротацию удобно не делать руками, а поручить инструменту с политикой: sanoid/syncoid для ZFS, zfs-auto-snapshot, cron-скрипт с lvremove по возрасту для LVM, lifecycle-политики самого облачного провайдера для managed-снапшотов. Ручная ротация почти гарантированно превращается в «забыли удалить» — а это прямой путь к деградации IOPS и заполненному месту, о цене которых подробно в статье про снапшоты, которые копятся годами.
Когда снапшоты стоит заменить полным бэкапом
Снапшот и бэкап решают разные задачи, и путаница между ними — источник половины проблем из этого текста. Снапшот живёт на том же томе, том же массиве, часто на том же хосте — он защищает от человеческой ошибки и позволяет быстро откатиться, но не защищает от отказа диска, массива или хоста целиком. Цепочка снапшотов, которая растягивается на недели и месяцы «на всякий случай», превращается в постоянный налог на IOPS (classic COW) или на место и скорость операций с метаданными (ZFS/Btrfs) — без прироста реальной защищённости данных по сравнению с нормальным бэкапом.
Разумная комбинация — короткоживущие локальные снапшоты (от минут до нескольких дней) для быстрого отката операционных ошибок, и отдельный бэкап-инструмент с копией на другом хосте или хранилище для реальной защиты и длинного хранения: restic, borgbackup, либо для ZFS — репликация zfs send/zfs receive на второй хост. Бэкап медленнее восстанавливается, чем откат по снапшоту, зато не создаёт постоянного оверхеда на живом томе и переживает отказ самого тома. Подробный разбор именно этого выбора — в статье снапшоты ZFS против полноценного бэкапа.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько снапшотов LVM можно держать одновременно без заметной деградации?
Единого числа нет — зависит от скорости хранилища и профиля записи. На classic dm-snapshot ориентируйтесь на один-два живых снапшота одновременно и проверяйте реальную просадку через fio по методике из этой статьи, а не по общим цифрам из интернета.
Замедляет ли ZFS-снапшот запись так же, как LVM?
Нет, механизм другой. ZFS и так пишет новые данные в новые блоки (файловая система изначально copy-on-write), поэтому наличие снапшота не добавляет дополнительного шага копирования на каждую запись. Цена проявляется в занятом месте и во времени операций с метаданными (list, destroy), а не в просадке IOPS на запись.
Что будет, если тонкий пул LVM переполнится из-за снапшотов?
В лучшем случае система заранее предупредит через мониторинг %data. В худшем — запись может быть приостановлена не только в переполнивший пул снапшот, но и в другие тома того же пула, до вмешательства администратора. Настройте алерты по проценту заполнения пула заранее, а не постфактум.
Можно ли снапшотить продовую БД каждый час без вреда?
Технически можно, но при высокой скорости записи каждый живой снапшот будет быстро расти в занятом месте (classic COW) или удерживать много уникальных блоков (ZFS), а на classic COW это ещё и IOPS-нагрузка. Для БД разумнее короткое окно жизни снапшота (снял — проверил — удалил) плюс полноценный инструмент бэкапа для настоящей retention-политики.
Как понять, что пора почистить старые снапшоты?
По метрикам, а не по расписанию «раз в месяц»: для LVM — snap_percent и %data пула, для ZFS — доля USEDBYSNAP в zfs list -o space и общий свободный процент пула. Порог для тревоги стоит ставить заметно ниже 100%, с запасом на скорость роста, а не по факту переполнения.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →