Знімки ZFS — одна з тих можливостей, що здаються шахрайством, поки вони тихо не перетворяться на просторову бомбу. Вони зазвичай не «займають місце» в момент створення, вони нічого не ламають, якщо їх забути (спочатку), і не кричать про увагу, поки пул не заповниться на 97% і ваша латентність запису не перетвориться на фільм жахів.
Цей матеріал про утримання знімків як операційну політику, а не філософську дискусію. Ми розглянемо реальні витрати знімків, чому «зберігайте всі» — пастка, як клони та holds перетворюють прибирання на кримінальну сцену, і як побудувати політику утримання, яка переживе корпоративну реальність: кілька команд, конфліктні пріоритети та автоматизацію з більшою впевненістю, ніж мудрістю.
Чому відбуваються просторові бомби
У production-е вибухи через знімки майже ніколи не походять від того, що ви думаєте. Люди звинувачують «занадто багато знімків», але кількість рідко є проблемою. Проблема — це швидкість змін, тривалість утримання і приховані анкерні точки, які заважають видаленню: клони, holds, залежності реплікації та «тимчасові» знімки, що стали постійними через недбалість.
Знімок ZFS — це точка в часі, що посилається на блоки. Його дешево створювати, бо це метадані й посилання — поки dataset не почне змінюватися. Коли блоки перезаписуються або видаляються у робочій файловій системі, знімок все ще посилається на старі блоки, тож ZFS має їх зберігати. З часом знімки стають музеєм перезаписаних блоків. Музеї гарні. Але музеї потребують будівель.
Є дві операційні брехні, що спричиняють більшість просторових бомб:
- Брехня №1: «Знімки безкоштовні.» Вони безкоштовні для створення, але не безкоштовні для збереження.
- Брехня №2: «Якщо dataset займає лише 2 ТБ, він не може споживати 10 ТБ.» Зі знімками це цілком можливо — бо знімки зберігають історичні версії блоків.
Щоб освіжити смак: політика утримання знімків — як нитка для зубів: усі погоджуються, що вона важлива, а всі вважають, що це робить хтось інший.
Цікаві факти та історичний контекст
Трохи контексту корисно, бо знімки ZFS не були створені як «функція продукту резервного копіювання». Вони були створені як примітив файлової системи з наслідками.
- Знімки ZFS — це конструкції метаданих з copy-on-write, а не блочні копії. «Копіювання» відбувається пізніше, коли живий dataset змінюється.
- Оригінальний ZFS з’явився у Sun Microsystems в середині 2000-х з радикальною ідеєю, що файлові системи повинні управляти томами й цілісністю разом.
- У традиційних реалізаціях LVM знімки часто мали продуктивнісні обриви при заповненні; знімки ZFS уникають цього конкретного механізму, але можуть все ще спричиняти фрагментацію й ріст метаданих.
- ZFS ввів send/receive як примітив реплікації першого класу — інкрементали залежать від лінії знімків, тож утримання взаємодіє з реплікацією більше, ніж очікують люди.
- «Простір, використовуваний знімками», — не є одним числом; ZFS розбиває його на referenced, logical vs physical та «used by snapshots», що плутає дашборди й людей однаково.
- Клони — це записувані знімки, і вони можуть блокувати видалення знімків, часто виявляючись лише під час прибирання о 2:00 ранку.
- ZFS підтримує user holds на знімках, саме щоб автоматичне прибирання не могло видалити критичні точки відновлення — анти-інструмент, що може стати анкером.
- Recordsize і стиснення впливають на вартість утримання. Схеми запису великих записів можуть утримувати більше історичних блоків, ніж інтуїтивно очікується.
- Більшість пулів «вмирають» через надто високе заповнення, а не через відмову одного диска. Високе заповнення посилює конкуренцію за виділення та фрагментацію; знімки часто прискорюють цей процес.
Модель простору знімків (що ZFS фактично рахує)
Щоб утримання було адекватним, потрібно розуміти, що ZFS рахує — а що ні. ZFS дає кілька різних видів «used»:
Referenced vs used vs logical
Referenced означає кількість даних, яку dataset (або знімок) представляв би, якби він був єдиним у системі. Це міра вмісту, а не вартості.
Used означає унікальні блоки, приписані цьому dataset або знімку в контексті всього іншого. Для знімків це може вводити в оману: «used» знімка — це блоки, що унікально зберігаються через нього, але ці блоки можуть також бути розділені між кількома знімками. Найбільш практичний вигляд в операціях зазвичай — розбивка на рівні dataset: usedbydataset, usedbysnapshots, usedbychildren, usedbyrefreservation.
Logical значення можуть перевищувати фізичні через стиснення. Це добре — поки хтось не планує ємність, використовуючи логічні цифри, і не дивується фізичній реальності.
Чому видалення файлів не звільняє місце (коли існують знімки)
Видалення файлу прибирає його посилання у живому dataset. Якщо знімок все ще посилається на старі блоки, ті блоки залишаються виділеними. З точки зору оператора, здається, що «rm не працює». Насправді працює. Просто ваші знімки збирають все як скупники.
Чому «просто видалити старі знімки» іноді теж не звільняє місце
Бо існують ще два анкерні фактори:
- Клони: якщо якийсь клон залежить від знімка, цей знімок не можна знищити, поки клон не буде promoted або знищений.
- Holds: знімок може бути утриманий адміністратором або автоматикою і відмовлятися видалятися, поки hold не знімуть.
Також, навіть коли ви видаляєте знімки, простір може не з’явитися одразу, якщо ви дивитесь не на ті метрики або якщо у вашому навантаженні домінують метадані й непрямі блоки. ZFS чесний, але не завжди одразу зрозумілий.
Ще жарт: облік простору ZFS — єдине місце, де «used» може означати «можливо», «залежить» і «так, але не так, як ви хочете» одночасно.
Побудова політики утримання, яка вас не підведе
Політика утримання — це контракт між вашими цілями відновлення та реаліями ємності. Якщо ви не можете сказати, від чого ви захищаєтесь — випадкові видалення, рансомвар, погані деплои, безшумна корупція, помилка оператора бази даних — ви будете переутримувати, поки пул не закінчиться.
Починайте з цілей відновлення, а не від почуттів
Є три ручки, які треба визначити:
- RPO (Recovery Point Objective): скільки даних ви готові втратити. Це визначає частоту знімків (щогодини, кожні 15 хвилин тощо).
- RTO (Recovery Time Objective): як швидко потрібно відновитися. Це впливає на те, скільки знімків зберігати локально для швидкого відкату.
- Горизонт історії: наскільки далеко назад вам потрібно відновлюватися від повільних помилок (погана конфігурація, дрейф даних). Це визначає щоденні/тижневі/місячні знімки та офсайтне збереження.
Практична початкова політика для багатьох змішаних навантажень виглядає так:
- Кожні 15 хвилин: зберігати 24 години
- Щогодини: зберігати 7 днів
- Щодня: зберігати 30 днів
- Щотижня: зберігати 12 тижнів
- Щомісяця: зберігати 12 місяців (часто тільки офсайт)
Це не універсальний шаблон; це відправна точка для розмови, що змушує витрати бути видимими.
Планування ємності: зарезервуйте запас для знімків
У production-е «пул на 80%» — це не просто відчуття; це межа. Вище приблизно 80–85% (залежно від recordsize, ashift, фрагментації, навантаження) виділення ускладнюється, і продуктивність дивно поводиться. Знімки полегшують дрейф вгору, бо вони невидимі, поки не стануть такими.
Замість питання «Скільки знімків ми можемо зберегти?», запитайте:
- Який наш щоденний churn (скільки даних змінюється за день)?
- Як довго ми зберігаємо знімки високої частоти?
- Скільки цього churn має залишатися локально проти реплікованого/офсайтного?
Якщо dataset має 2 ТБ активних даних, але churn становить 300 ГБ/день (бази даних, CI-артефакти, образи VM), то «зберігати 30 щоденних знімків» — це не «зберегти 2 ТБ плюс трохи». Це потенційно «зберегти до ~9 ТБ історичних перезаписаних блоків», мінус ефект стиснення/дедупа. Ось така математика, яку оператори мають показати менеджменту, перш ніж менеджмент поставить нову ініціативу на той самий пул.
Шарове утримання: локальний швидкий відкат проти віддаленої довгої історії
Тримати глибоку історію локально дорого і часто непотрібно. Використовуйте локальні знімки для вікон швидкого відкату (години-дні), а для довшої історії — реплікаційні цілі (інший пул, інший сайт), де тиск на ємність і продуктивність інший.
Дві застереження:
- Інкрементальна реплікація залежить від ланцюгів знімків. Якщо ви видалите знімок, який очікує віддалений інкремент, ви можете примусити повне повторне відправлення — болісне по смузі й часу.
- Цілі реплікації мають власну історію утримання. «Ми реплікуємо все» — це не політика утримання; це спосіб відтворити ваші помилки десь ще.
Межі dataset: не знімайте «ящик з мотлохом»
Якщо ви робите знімки dataset, що містить одночасно «критичну конфігурацію» і «відновлюваний кеш», ваші витрати на утримання домінуватимуть через кешовий churn. Розділіть dataset за лініями утримання та churn:
- Відокремте бази даних від логів та тимчасових файлів.
- Відокремте образи VM від ISO-кешів і артефактів збірки.
- Відокремте домашні директорії від гігантських папок завантажень (так, це реальна річ).
Як SRE, я бачив, як утримання «провалюється», бо політика була правильна, але застосована до неправильної межі dataset. Файлова система була структурована як ящик з мотлохом, і знімки зробили саме те, що їм сказали: зберегти історію всього, включно зі сміттям.
Іменування, теги та можливість виявлення
Утримання знімків — частково психологія. Якщо ніхто не може сказати, для чого знімок, ніхто його не видалить. Якщо ніхто не може сказати, які знімки безпечні, прибирання стає політичними торгами.
Використовуйте схему іменування, що кодує намір
Практична схема включає:
- Мітку часу в сортувальному форматі (UTC вам друг)
- Клас частоти (15m, hourly, daily, weekly)
- Творець або система (cron, backup, operator)
- Опціональний номер заявки/зміни для ручних знімків
Приклад шаблонів (виберіть один і дотримуйтеся):
pool/app@auto-2025-12-25T1200Z-hourlypool/app@manual-INC12345-2025-12-25T1200Z
Holds — не смітник
Holds на знімках існують, щоб заборонити видалення. Це корисно під час інциденту або розслідування, коли потрібен заморожений стан. Але це не механізм утримання. Holds повинні мати:
- Рядок причини, що включає хто/чому
- Процес закінчення терміну (перегляд holds щотижня)
- Документованого власника
Клони: ставтесь до них як до production-ресурсів
Клони чудові для швидких тестових середовищ і оновлень БД. Вони також — причина №1, чому «знищити старі знімки» не вдається під час екстреного прибирання. Якщо ви дозволяєте ad-hoc клонування, треба інвентаризувати клони і або:
- Promote клон, щоб він більше не залежав від оригінального ланцю знімків, або
- Обмежити клонування контролюваними пайплайнами з часом життя
Шаблони автоматизації (і що вони ламають)
Автоматизація — єдиний шлях, щоб утримання працювало в масштабі. Це також шлях випадково знищити найкращу точку відновлення або зберігати знімки назавжди через один не врахований код повернення.
Два режими автоматизації: «за кількістю» vs «за часом»
За кількістю означає «зберігати останні N». Це просто, але небезпечно: якщо знімки перестають створюватися тиждень, ви можете зберегти тижневі прогалини і видалити останню відому хорошу точку, бо вона «стара».
За часом означає «зберігати все новіше за X». Це узгоджується з людськими очікуваннями та мовою RPO/RTO. Його трохи складніше коректно реалізувати при наявності кількох частот.
Використовуйте ієрархічні політики, а не одне велике правило
Утримання найкраще працює як шари:
- Висока частота знімків, коротке утримання (швидкий відкат)
- Низька частота знімків, середнє утримання
- Архівні знімки, довге утримання (часто віддалено)
Dry-run та запобіжні засоби
У production прибирання повинно підтримувати:
- Dry-run перелік кандидатів
- Видалення обмеженими батчами (щоб уникнути затримок txg і паніки операторів)
- Логування дій і причин
- Відмову від операції, якщо пул деградований (ви не хочете додавати навантаження)
Три міні-історії з корпоративного світу
1) Інцидент, спричинений хибним припущенням: «Знімки не рахуються»
Компанія мала сервіс NFS на базі ZFS, що використовувався дюжиною внутрішніх команд. Дашборд показував первинний dataset у розумних межах, і пул був стабільним місяцями. Потім, протягом довгих вихідних, батч-джоб виконав перезапис даних — той самий загальний розмір, але інші блоки. У вівторок вранці пул був на 98% і латентність NFS виглядала як сейсмограф.
On-call виконав типове прибирання: очистив старі логи, видалив тимчасові експортовані дані, навіть видалив кілька великих «очевидних» каталогів. Місце не зрушило. Далі зазвичай починається звинувачення: «ZFS брешуть», «монітор помиляється», «хтось примонтував не той пул». Жодне з цього не було правдою.
Справжній винуватець — політика утримання, що існувала тільки в вікі. Знімки робилися щогодини і ніколи не видалялися, бо джоб прибирання тихо впав після невеликого оновлення ОС, що змінило формат виводу команди. Хибне припущення було в тому, що «знімки — це метадані і не мають значення». Мали — бо churn від перезапису батчу зберігався щогодини місяцями.
Відновлення було брудним, але повчальним. Вони виявили dataset з найвищими usedbysnapshots, призупинили шумний батч-джоб і видаляли знімки батчами, спостерігаючи за використанням пулу і латентністю. Також додали моніторинг кількості знімків і простору, зайнятого знімками, плюс алерт при падінні джоба утримання. Найцінніша зміна була культурна: утримання знімків стало конфігурацією з контролем змін, а не «ймовірно працює» уcron.
2) Оптимізація, що відкотилася: «Давайте робити знімки кожні 5 хвилин»
Платформна команда хотіла майже миттєвий відкат для флоту build-агентів і тестових середовищ. Хтось запропонував: «Робити знімки кожні п’ять хвилин і зберігати їх два тижні.» На слайдах виглядало чудово: швидкі відновлення, низькі зусилля інженерів, мінімальний ризик. Те, що build-агенти генерують й видаляють величезні обсяги даних, було ввічливо проігноровано.
Це працювало — коротко. Відновлення були швидкими, розробники задоволені. Потім пул почав фрагментуватися. Виділення ускладнилося, синхронні записи уповільнилися, і метадані почали рости. Кількість знімків виросла до тисяч на dataset, і перелік знімків став настільки повільним, що їхня автоматизація іноді таймаутилася. «Оптимізація» перетворилася на самосаботаж.
Відкат не через те, що знімки погані. А через те, що високочастотні знімки на високочастотних, низькоцінних даних — жахливий компроміс. Команда врешті розділила dataset: критична конфігурація і невеликий стан отримали агресивні знімки, а build-рабочий простір перемістили до dataset з мінімальним утриманням (або без нього), плюс окреме сховище артефактів з реальною lifecycle-політикою. Продуктивність відновилась, операції зі знімками знову стали надійними, і історія відкатів залишилась для даних, які цього дійсно варті.
Урок: частота знімків — не ознака серйозності. Це функція вартості. Трактуйте її відповідно.
3) Нудна, але правильна практика, що врятувала день: «Квартальні відпрацювання відновлення й дисципліна щодо holds»
В іншій організації команда зберігання не була яскравою. Вони мали запланований перегляд політики щоквартально. Вони тестували відновлення з знімків і з реплікованих цілей. Вони тримали невеликий перелік «золотих знімків» для аудитів і релізів, і контролювали holds як паркувальні дозволи: потрібна причина, потрібен власник, і воно спливає, якщо не продовжено.
Потім пройшов поганий деплой і тонко пошкодив dataset — не повне знищення, більше «все виглядає нормально, поки не запуститься білінгова задача». Команда застосунку хотіла відкотитись, але інцидент виявили через кілька днів. Ось де ad-hoc політики утримання зазвичай фейлять: «корисні» знімки вже пішли, а ті, що лишилися, надто нові.
Але нудна практика окупилась. Команда мала щоденні знімки на 30 днів локально і щомісячні знімки, збережені рік на репліці. Вони знайшли чистий щоденний знімок до вікна корупції, перевірили його в клоні і відновили без драм. Бізнес нічого не дізнався — ознака правильної роботи.
Висновок не в «зберігайте все». А в «зберігайте те, що потрібно бізнесу, і доведіть, що можете його відновити». Знімки, які не відновлювалися — теоретичні активи. У інциденті теорія дорога.
Практичні завдання: команди та інтерпретація
Нижче — практичні завдання, які можна виконати на ZFS-системі. Команди вказані в уніфікованому форматі підказки; підставте імена pool/dataset під ваше середовище.
Завдання 1: Отримати загальний вигляд здоров’я та ємності пулу
cr0x@server:~$ zpool status -v
pool: tank
state: ONLINE
scan: scrub repaired 0B in 02:31:44 with 0 errors on Sun Dec 22 02:31:45 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
errors: No known data errors
Інтерпретація: Якщо пул деградований, відкладіть агресивне видалення знімків або перестановки реплікації; не варто додавати навантаження. Також перевірте давність scrub — старі scrubs плюс високе заповнення — ризикова комбінація.
Завдання 2: Подивитися ємність пулу та сигнали фрагментації
cr0x@server:~$ zpool list -o name,size,alloc,free,cap,health
NAME SIZE ALLOC FREE CAP HEALTH
tank 36.2T 29.8T 6.4T 82% ONLINE
Інтерпретація: На ~80% починайте звертати увагу. Якщо ви понад 85–90%, вікно для прибирання знімків стає ризиковим для production.
Завдання 3: Показати розбивку простору dataset, включно зі знімками
cr0x@server:~$ zfs list -o name,used,available,usedbydataset,usedbysnapshots,usedbychildren,mountpoint tank/app
NAME USED AVAIL USEDBYDATASET USEDBYSNAPSHOTS USEDBYCHILDREN MOUNTPOINT
tank/app 8.2T 5.9T 2.1T 5.7T 420G /tank/app
Інтерпретація: Це класичний підпис «просторової бомби»: dataset займає лише 2.1T, а знімки утримують 5.7T. Видалення файлів не допоможе, поки знімки не обрізані.
Завдання 4: Перелічити знімки з used і refer
cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -s creation tank/app | tail -n 6
tank/app@auto-2025-12-24T1800Z-hourly 12.3G 2.1T Wed Dec 24 18:00 2025
tank/app@auto-2025-12-24T1900Z-hourly 10.9G 2.1T Wed Dec 24 19:00 2025
tank/app@auto-2025-12-24T2000Z-hourly 11.7G 2.1T Wed Dec 24 20:00 2025
tank/app@auto-2025-12-24T2100Z-hourly 14.2G 2.1T Wed Dec 24 21:00 2025
tank/app@auto-2025-12-24T2200Z-hourly 13.8G 2.1T Wed Dec 24 22:00 2025
tank/app@auto-2025-12-24T2300Z-hourly 15.1G 2.1T Wed Dec 24 23:00 2025
Інтерпретація: used знімка тут — унікальний інкрементальний простір. Якщо ці значення великі і стабільні, ваш churn високий. Якщо вони підскакують — шукайте батч-перезаписи, компактування або ротації логів, що перезаписують великі файли.
Завдання 5: Знайти найгірші dataset за накладом знімків
cr0x@server:~$ zfs list -r -o name,usedbydataset,usedbysnapshots -s usedbysnapshots tank | head -n 10
NAME USEDBYDATASET USEDBYSNAPSHOTS
tank 128K 0B
tank/home 640G 120G
tank/vm 3.1T 2.8T
tank/app 2.1T 5.7T
tank/app/db 1.4T 3.9T
tank/app/logs 180G 1.1T
tank/ci 900G 4.4T
tank/ci/workspace 700G 4.2T
tank/backup 1.9T 900G
Інтерпретація: Зазвичай винуватці очевидні: CI workspace, логи, образи VM. Виправлення рідко буває в «безпечному видаленні знімків всліпу». Це «припиніть знімати мінливий мотлох або зменшіть його утримання».
Завдання 6: Перевірити holds, що блокують видалення
cr0x@server:~$ zfs holds tank/app@auto-2025-12-01T0000Z-daily
NAME TAG TIMESTAMP
tank/app@auto-2025-12-01T0000Z-daily audit-freeze Thu Dec 4 09:12 2025
Інтерпретація: Цей знімок не видалиться, поки hold не буде знято. Тег каже, хто/чому — якщо ваш процес достатньо дисциплінований, щоб вимагати осмислених тегів.
Завдання 7: Скасувати hold (обережно)
cr0x@server:~$ sudo zfs release audit-freeze tank/app@auto-2025-12-01T0000Z-daily
Інтерпретація: Зняття holds має бути задокументованим. Якщо ви робите це ad-hoc під час інциденту з місцем, запишіть, що й чому зняли. Майбутній ви захоче цей слід.
Завдання 8: Виявити клони, що перешкоджають знищенню знімка
cr0x@server:~$ zfs get -H -o name,value clones tank/app@auto-2025-11-15T0000Z-daily
tank/app@auto-2025-11-15T0000Z-daily tank/dev/app-test
Інтерпретація: Цей знімок має залежний клон. Ви не можете зруйнувати ланцюг знімків необережно, поки клон не буде вирішений.
Завдання 9: Promote клона, щоб прибрати залежність від оригінального знімка
cr0x@server:~$ sudo zfs promote tank/dev/app-test
Інтерпретація: Promotion змінює лінійність: клон стає основним, а оригінал стає залежним. Це може бути вірним кроком, коли дев-середовище випадково стало довгоживучим і потрібно звільнити старий ланцюг знімків. Робіть це свідомо; це не косметична зміна.
Завдання 10: Безпечно видаляти знімки батчами
cr0x@server:~$ zfs list -t snapshot -o name -s creation tank/app | head -n 5
NAME
tank/app@auto-2025-10-01T0000Z-daily
tank/app@auto-2025-10-02T0000Z-daily
tank/app@auto-2025-10-03T0000Z-daily
tank/app@auto-2025-10-04T0000Z-daily
cr0x@server:~$ sudo zfs destroy tank/app@auto-2025-10-01T0000Z-daily
cr0x@server:~$ sudo zfs destroy tank/app@auto-2025-10-02T0000Z-daily
Інтерпретація: Під час інциденту з повним пулом видалення тисяч знімків одночасно може спричинити довгі операції і налякати людей. Робіть батчами, спостерігайте вплив і уникайте погіршення латентності, намагаючись вирішити проблему простору.
Завдання 11: Видалити діапазон за іменами знімків (коли доречно)
cr0x@server:~$ sudo zfs destroy -n tank/app@auto-2025-10-01T0000Z-daily%auto-2025-10-31T0000Z-daily
would destroy tank/app@auto-2025-10-01T0000Z-daily
would destroy tank/app@auto-2025-10-02T0000Z-daily
...
would destroy tank/app@auto-2025-10-31T0000Z-daily
cr0x@server:~$ sudo zfs destroy tank/app@auto-2025-10-01T0000Z-daily%auto-2025-10-31T0000Z-daily
Інтерпретація: Спершу використовуйте -n. Видалення діапазону потужне і небезпечне; це спосіб очистити правильно за хвилини або зруйнувати ваше вікно відновлення за секунди.
Завдання 12: Виміряти churn за записаними байтами (наближено)
cr0x@server:~$ zfs get -o name,property,value -s local,received,default written tank/app
NAME PROPERTY VALUE
tank/app written 14.8T
Інтерпретація: written — корисна підказка про те, скільки даних записано в dataset (не точно «churn», але корелює). Якщо воно стрімко зростає — ваші витрати на утримання теж зростатимуть.
Завдання 13: Перевірити квоти й резервації, що роблять простір «відсутнім»
cr0x@server:~$ zfs get -o name,property,value quota,refquota,reservation,refreservation tank/app
NAME PROPERTY VALUE
tank/app quota none
tank/app refquota none
tank/app reservation none
tank/app refreservation 500G
Інтерпретація: refreservation може резервувати місце навіть коли ви намагаєтесь звільнити простір. Це не зло; це спосіб гарантувати простір для dataset. Але під час інциденту може дивувати.
Завдання 14: Побачити, які знімки посилаються bookmark-ами реплікації чи логікою (перевірки)
cr0x@server:~$ zfs list -t bookmark -o name,creation -s creation tank/app
NAME CREATION
tank/app#replica-2025-12-20T0000Z Sat Dec 20 00:00 2025
tank/app#replica-2025-12-21T0000Z Sun Dec 21 00:00 2025
Інтерпретація: Bookmarks можуть фіксувати інкрементальну реплікацію без тримання повного знімка на відправнику. Якщо ви їх використовуєте, інтегруйте їх у політику утримання навмисно — не натрапляйте на них під час прибирання.
Завдання 15: Перевірити, що видалення знімків справді зменшило usedbysnapshots
cr0x@server:~$ zfs list -o name,usedbydataset,usedbysnapshots tank/app
NAME USEDBYDATASET USEDBYSNAPSHOTS
tank/app 2.1T 5.7T
cr0x@server:~$ sudo zfs destroy tank/app@auto-2025-10-01T0000Z-daily%auto-2025-10-15T0000Z-daily
cr0x@server:~$ zfs list -o name,usedbydataset,usedbysnapshots tank/app
NAME USEDBYDATASET USEDBYSNAPSHOTS
tank/app 2.1T 4.9T
Інтерпретація: Добре: snapshot-used впав. Якщо ні, ймовірно ви видалили знімки, що не тримали багато унікальних даних, або вас блокують клони/holds десь ще, або churn все ще триває.
План швидкої діагностики
Це «підходьте до стресового пулу і знайдіть вузьке місце швидко» план. Він впорядкований для швидкості отримання сигналу, а не академічної чистоти.
Перше: чи просто пул занадто заповнений або нездоровий?
cr0x@server:~$ zpool list -o name,cap,alloc,free,health
NAME CAP ALLOC FREE HEALTH
tank 92% 33.3T 2.9T ONLINE
cr0x@server:~$ zpool status -x
all pools are healthy
Інтерпретація: Якщо ви >90% завантажені, ставтеся до всього як до термінового. Продуктивність ZFS і поведінка виділення погіршуються при зменшенні вільного місця. Якщо пул деградований, уникайте великих руйнівних операцій і зосередьтеся на швидкому зниженні ризику.
Друге: хто споживає простір — dataset, знімки, діти, резервації?
cr0x@server:~$ zfs list -o name,used,available,usedbydataset,usedbysnapshots,usedbychildren,usedbyrefreservation -r tank | head -n 20
NAME USED AVAIL USEDBYDATASET USEDBYSNAPSHOTS USEDBYCHILDREN USEDBYREFRESERVATION
tank 29.8T 6.4T 128K 0B 29.8T 0B
tank/app 8.2T 5.9T 2.1T 5.7T 420G 0B
tank/ci 5.5T 5.9T 900G 4.4T 200G 0B
tank/vm 5.9T 5.9T 3.1T 2.8T 0B 0B
Інтерпретація: Вирішіть, де діяти. Якщо usedbysnapshots домінує — допомагає обрізка. Якщо usedbydataset домінує — потрібне реальне видалення або міграція. Якщо usedbyrefreservation велике — перегляньте резервації.
Третє: що перешкоджає видаленню знімків?
Перевірте holds і клони для кожного знімка, який плануєте видалити.
cr0x@server:~$ zfs holds tank/ci@auto-2025-11-01T0000Z-daily
no datasets available
cr0x@server:~$ zfs get -H -o value clones tank/ci@auto-2025-11-01T0000Z-daily
-
Інтерпретація: Якщо є holds або клони, ваш план прибирання має включати зняття holds або промоцію/знищення клонів. Інакше ви витратите час на «видалення» знімків, які не можуть бути видалені.
Четверте: чи триває churn зараз?
Якщо ви обрізаєте під час того, як навантаження переписує терабайти, ви ніби гребете човен з діркою. Призупиніть шумну задачу, якщо можливо, або тимчасово зменшіть навантаження на запис.
cr0x@server:~$ zfs get -o name,property,value written tank/ci/workspace
NAME PROPERTY VALUE
tank/ci/workspace written 92.4T
Інтерпретація: Великі значення written не є прямим доказом поточного churn, але підказують, що цей dataset — машина churn і не повинен мати глибокого високочастотного утримання.
П’яте: якщо скарга на латентність, підтвердіть I/O тиск окремо
Інциденти простору ZFS часто виявляються як інциденти латентності. Не припускайте, що це «просто мережа» або «просто аплікація». Підтвердіть, що пул під I/O-навантаженням, перед тим як робити дії, що його посилять.
cr0x@server:~$ zpool iostat -v 5 3
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 29.8T 6.4T 88 2100 8.2M 310M
raidz2-0 29.8T 6.4T 88 2100 8.2M 310M
sda - - 22 520 2.0M 78M
sdb - - 23 530 2.1M 79M
sdc - - 21 520 2.0M 76M
sdd - - 22 530 2.1M 77M
-------------------------- ----- ----- ----- ----- ----- -----
Інтерпретація: Якщо пул насичений, видалення знімків та інші важкі операції з метаданими можуть погіршити хвостову латентність. Проводьте батч-операції та плануйте прибирання в позаробочий час, коли можливо — якщо тільки ви вже не в зоні ураження.
Поширені помилки, симптоми, виправлення
Помилка 1: «Ми все збережемо, зберігання дешеве»
Симптоми: Використання пулу поступово зростає попри «відсутність росту» видимих даних; прибирання стає аварійною роботою; відновлення сповільнюються, бо система постійно близька до повного.
Виправлення: Визначте цілі відновлення і обмежте локальне утримання. Перенесіть довгу історію на окрему реплікацію з власним планом ємності.
Помилка 2: Знімки високочастотних dataset (CI, логи, кеші) з тією ж політикою, що й бази даних
Симптоми: usedbysnapshots переважає над usedbydataset; тисячі знімків; зростання фрагментації і підвищення латентності запису.
Виправлення: Розділіть dataset за класом churn. Застосовуйте агресивні знімки тільки до цінного, низькоchurn стану. Для churn-даних тримайте коротке утримання або взагалі ні; покладайтеся на lifecycle артефактів вищого рівня.
Помилка 3: Ігнорування holds, поки вони не стануть постійними
Симптоми: Джоб утримання «успішний», але кількість знімків ніколи не падає; zfs destroy видає помилки; оператори знаходять «таємні holds» під час інциденту.
Виправлення: Операційна дисципліна: holds вимагають власника/причини/терміну. Запускайте щотижневий звіт по held snapshots і переглядайте їх.
Помилка 4: Дозвіл на клонування без життєвого циклу власності
Симптоми: Видалення знімків не вдається через залежні клони; старі dev/test середовища перешкоджають прибиранню; команда зберігання стає нежаданим власником покинутих клонів.
Виправлення: Ведіть клони як первинні ресурси. Наводьте термін життя або вимагаєте промоцію з явною власністю перед тим, як клон може жити довше короткого вікна.
Помилка 5: Використання «keep latest N» без захисту від пропусків
Симптоми: Після простою в створенні знімків, прибирання видаляє старі знімки і залишає тільки нові — знищуючи здатність відкотитись за межі вікна простою.
Виправлення: Віддавайте перевагу політиці за часом. Якщо використовуєте за кількістю, реалізуйте «мінімальний вік для видалення» і «мінімальне вікно історії» як запобіжники.
Помилка 6: Видалення знімків однією величезною операцією в пікове навантаження
Симптоми: Зростання латентності; довгі zfs destroy; таймаути аплікацій; оператори панікують і переривають процес.
Виправлення: Видаляйте батчами, вимірюйте вплив і надавайте пріоритет знімкам, що тримають найбільше унікального простору. Плануйте масові видалення в позаробочий час, коли можливо.
Помилка 7: Невідстеження збоїв автоматизації утримання
Симптоми: Все виглядає добре, поки не стане погано; кількість знімків тихо зростає; скрипти прибирання тихо падають після змін ОС/інструментів.
Виправлення: Алерт на «останнє успішне виконання джобу утримання» і на кількість знімків/простір, що перевищують пороги. Ставте утримання як production-сервіс.
Контрольні списки / поетапний план
Покроково: Спроєктуйте політику утримання, що відповідає реальності
- Класифікуйте dataset за бізнес-цінністю і churn: критичний стан, важливий стан, відновлюваний, кеші/логи.
- Визначте RPO/RTO по класах (не по точці монтування файлової системи).
- Виберіть частоти знімків, що відповідають RPO: наприклад, 15m для критичного стану, hourly/daily для менш критичного.
- Встановіть локальні вікна утримання з запасом: тримайте менше локально, ніж емоційно хочеться, і більше віддалено, ніж зараз маєте.
- Плануйте ємність використовуючи оцінки churn: явно бюджетуйте запас для знімків (і переглядайте щоквартально).
- Визначте конвенції імен і впровадьте їх в автоматизацію.
- Визначте політику holds: дозволені причини, необхідні теги, термін дії, звітність.
- Визначте політику клонів: хто може створювати, де, на який термін, і що відбувається після закінчення.
- Автоматизуйте створення і обрізку знімків з dry-run і логуванням.
- Тестуйте відновлення щоквартально: і простий відкат, і повний робочий процес відновлення.
Покроково: Екстрене прибирання, коли пул майже повний
- Зупиніть витік: призупиніть high-churn задачі, зупиніть runaway CI, зупиніть лог-шторм, відключіть неважливі записи.
- Підтвердіть тиск:
zpool list,zfs listз розбивкою по знімках. - Виявте головних порушників: dataset з найбільшим
usedbysnapshots. - Перевірте блоки: holds і клони на найстаріших знімках.
- Видаляйте батчами починаючи зі знімків, найменш потрібних (старі hourly перед daily/weekly, якщо політика не каже інакше).
- Перевіряйте після кожного батчу: cap пулу, латентність і метрики snapshot-used.
- Документуйте зроблене і чому; потім виправте автоматизацію/політику, що дозволили це статися.
Часті питання
1) Чи знімки ZFS одразу споживають простір?
Зазвичай ні: створення знімка в основному — метадані. Витрати простору з’являються, коли живий dataset змінюється і старі блоки треба зберігати для знімків.
2) Чому видалення файлів не звільняє місце в моїй ZFS?
Якщо існують знімки, видалені/перезаписані блоки можуть все ще посилатися з цих знімків. Щоб звільнити місце, потрібно видалити знімки (або перенести дані в новий dataset без цих знімків).
3) Який найкращий показник, щоб побачити вплив знімків?
Використовуйте zfs list з usedbydataset і usedbysnapshots. Це покаже, чи знімки домінують у споживанні. Показник used на рівні знімка допомагає виявити патерни churn, але може вводити в оману, якщо багато знімків ділять блоки.
4) Чи безпечно видаляти знімки?
Технічно безпечно — так, якщо ви розумієте, які точки відновлення втрачаєте і не ламаєте очікувань реплікації. Технічна дія видалення безпечна; бізнес-наслідки можуть бути незворотніми.
5) Чому я не можу знищити знімок? Він каже, що зайнятий.
Поширені причини: у нього є hold або залежні клони. Перевірте zfs holds і zfs get clones. Зніміть holds або вирішіть клони (destroy/promote) перед повторною спробою.
6) Чи варто зберігати знімки на тому самому пулі, що й продакшн дані?
Для коротких вікон відкату — так. Для довгої історії зазвичай краще реплікувати на інший пул або систему. Один пул — це одна домен відмови і одна домен ємності — знімки це не змінюють.
7) Скільки знімків — це «занадто багато»?
Універсального числа немає. «Занадто багато» — коли перелік/управління знімками стає повільним, джоби утримання таймаутяться або простір, утримуваний знімками, забирає запас. Для високочастотних churn dataset «занадто багато» настає швидше.
8) Чи важливі стиснення і recordsize для утримання знімків?
Так. Стиснення змінює фізичний слід; recordsize і патерни запису впливають, скільки старих даних потрібно зберігати. Перезаписи великих записів можуть зробити утримання дорогим, навіть якщо «розміри файлів не змінилися».
9) Чи можна покладатися на знімки як єдину резервну копію?
Ні, якщо вам важлива доступність при відмові обладнання, втраті пулу або інциденті сайту. Знімки чудові для швидкого відкату і локального відновлення; бекапи/реплікація дають розділення і живучість.
10) Чому видалення знімків не знизило використання пулу одразу?
Типові причини: ви видалили знімки, які не тримали багато унікального простору; клони/holds все ще анкерують дорогі частини; навантаження продовжує churn; або ви дивитесь не на ті метрики на рівні dataset/pool. Перевірте usedbysnapshots і перевірте блокуючі фактори.
Висновок
Знімки ZFS — це суперсила. Їхня ціна в тому, що час стає споживачем сховища. Якщо ви не поставите межі часу — частоту, утримання і намір — ваш пул зрештою заплатить рахунок з відсотками, часто в тиждень, коли ви не можете дозволити собі драму.
Політика, що запобігає просторовим бомбам, не складна: вирівняйте знімки з цілями відновлення, відокремте churn-дані, автоматизуйте обрізку з запобіжними засобами, і тримайте holds/клони на повідку. Решта — операційна дисципліна: моніторте важливе, відпрацьовуйте відновлення і ставте утримання як production-інфраструктуру — а не надійний скрипт у cron.