ZFS-знімки: суперсила, яка може заповнити ваш пул

Було корисно?

ZFS-знімки — це те, що найближче до подорожі в часі, що мають інженери зберігання даних. Вони дозволяють відкотити dataset, відновити файл, який «ніби не видаляли», і відправити консистентні дані на іншу машину без зупинки сервісів. Ви можете робити їх щохвилини і спати спокійніше — поки не прокинетеся і не побачите пул на 98% та кластер, який раптово став ставитися до fsync() як до пропозиції.

Цей матеріал для людей, що експлуатують продакшн-системи, а не для лабораторних демо. Ми розглянемо, скільки знімки насправді коштують, як облік місця може вас обманути (чесно), і як керувати збереженням, не перетворивши розклад знімків на повільну дію відмови обслуговування. По дорозі: команди, які можна виконати вже сьогодні, три історії з корпоративного життя, які ви впізнаєте, і швидкий план діагностики, коли пул заповнюється швидше, ніж сідає батарея в пейджері.

Що таке знімок ZFS насправді (і що ні)

ZFS-знімок — це лише доступ для читання до стану dataset на певний момент часу. ZFS працює за принципом copy-on-write: коли дані змінюються, ZFS записує нові блоки і потім оновлює метадані, щоб на них вказати. Старі блоки залишаються доти, доки на них щось посилається. Знімок — це просто «щось інше, що все ще посилається на старі блоки».

Ось чому знімки швидко створюються: ZFS не копіює ваш dataset; він просто закріплює посилання. І також це пояснює, чому знімки можуть «займати» багато місця пізніше: не тому, що вони ростуть самі по собі, а тому, що вони перешкоджають звільненню старих блоків, коли живий dataset змінюється.

Ментальна модель, яка запобігає відмовам

Уявіть dataset як плейлист, а не папку. Блоки — це пісні. Коли ви «редагуєте» плейлист, ZFS не редагує пісні на місці; він записує нові пісні і вказує на них у плейлисті. Знімок — це збережена версія плейлиста, яка продовжує вказувати на старі пісні. Якщо ви продовжуєте редагувати, ви накопичуєте старі пісні, на які ще посилаються знімки.

Якщо метафора здається занадто м’якою для продакшна: знімки — це «корені збирача сміття». Вони тримають блоки живими. Якщо ви створите багато коренів і будете сильно міняти «кучку», ви заповните пам’ять. Тут пам’ять — це ваш пул.

Знімки — це не резервні копії (переважно)

Знімки захищають від логічних проблем: випадкових видалень, невдалих деплоїв, рансомвару, який ви помітили швидко, або того скрипта, що «лише видаляє старі файли», але має помилку в шляху. Резервні копії захищають від фізичних і екзистенційних проблем: втрати пулу, помилок оператора, що знищує знімки, пожежі, крадіжки і «ми мігрували не той dataset і не помітили це місяць».

Ви можете перетворити знімки на резервні копії, реплікуючи їх кудись ще (наприклад, zfs send/receive) з незалежною політикою збереження. До того моменту знімки — це страховальна сітка на тому самому трапеці.

Жарт №1: знімок — це як «скасувати», тільки він ніколи не забуває і виставляє вам рахунок у терабайтах.

Факти та контекст: чому знімки стали важливими

Трохи історичного й технічного контексту допомагає пояснити, чому знімки ZFS здаються магічними — і чому вони можуть здивувати команди, які прийшли з традиційних файлових систем і LVM.

  1. ZFS постачався зі знімками як можливістю першого класу, коли багато файлових систем розглядали знімки як додаток (менеджер томів, фірмове рішення або пропрієтарні інструменти).
  2. Copy-on-write — це те, що дозволило: ZFS може робити знімки дешево, бо ніколи не перезаписує живі блоки на місці; він записує нові блоки і змінює вказівники.
  3. Облік простору еволюціонував: ранні реалізації й старі інструменти часто плутали «referenced», «used» і «logical» розміри, що призводило до невідповідних дашбордів у змішаних середовищах.
  4. У Solaris-шопах нормалізували агресивні розклади знімків задовго до того, як контейнери зробили «незмінну інфраструктуру» модною; щоденні/годинні/хвилинні патерни були поширені в корпоративних NAS робочих навантаженнях.
  5. Знімки scoped на dataset, а не на пул. Це важливо, коли люди припускають, що «одна політика збереження для всього пулу» поводитиметься однаково скрізь.
  6. Клони зробили знімки більш небезпечними (в хорошому сенсі): клон залежить від свого знімка. Видалення блокується, і ваша задача «обрізати старі знімки» раптово стає брехнею.
  7. VM-образи та бази даних змінили гру: навантаження з випадковими записами швидко перемішують блоки, через що знімки накопичують посилання на старі блоки набагато швидше, ніж навантаження, що переважно додають.
  8. «Пул заповнений» став окремим типом інциденту, бо поведінка ZFS при високій заповненості значно погіршує продуктивність; це не просто «немає місця», це «все сповільнюється і починаються помилки».
  9. Дешеві знімки ускладнили політику збереження: як тільки команди дізналися, що можна тримати 30 днів «безкоштовно», хтось попросить 365 днів «через комплаєнс».

Неприємна правда: як знімки «використовують» простір

Найпоширеніше хибне припущення: «знімки дешеві, отже знімки малі». Створення дешеве. Простір — ні.

Три види «розміру», які ви побачите

ZFS повідомляє кілька метрик, і вони відповідають на різні питання:

  • logicalused: скільки даних логічно зберігається (ігнорує компресію, копії тощо).
  • used: скільки місця використано на диску з перспективи цього dataset (включає такі речі, як знімки залежно від показаних прапорів/властивостей).
  • referenced: простір, який звільнився б, якби dataset було знищено (унікальний живий вигляд, виключаючи простір, утримуваний тільки знімками).
  • usedbysnapshots / usedbydataset / usedbychildren: розбивка, яка зупиняє суперечки на нарадах.

Знімки «використовують» простір блоків, які більше не посилаються живим dataset, але все ще посилаються одним або кількома знімками. Отже використання знімків пропорційне швидкості змін, а не загальному розміру dataset. Dataset на 10 ТБ із низьким churn може мати роки знімків з помірними накладними витратами; datastore віртуальних машин на 500 ГБ з високим churn може з’їсти пул за вихідні.

Чому видалення файлів іноді не звільняє простір

Ви видалили каталог на 200 ГБ. Користувачі радіють. Моніторинг не рухається. Це робота знімків: вони все ще посилаються на блоки, тому пул не може їх звільнити. Саме тому «скрипти очищення» можуть вводити в оману у системах з великою кількістю знімків: вони зменшують живий посиланий простір, але не змінюють розподіл пулу доти, доки старі знімки не будуть видалені.

«Але ми знімкуємо лише /var/log, і наскільки це може бути погано?»

Патерни додавання в кінець файлу дружні до знімків. Але багато систем не є append-only:

  • VM-образи: метадані файлової системи гостьової ОС змінюються, дрібні випадкові записи, ротація логів усередині гостьової ОС.
  • Бази даних: чекпоїнти й компактинг можуть перезаписувати великі ділянки.
  • Кеші збірки та CI workspace: патерни видалити-і-створити «перемішують» усе.
  • Шари контейнерів: часті перебудови; багато змін маленьких файлів.

Крайня межа «пул заповнений» реальна

Багато команд трактують 95% використання як «ще 5% вільно». У ZFS ці останні 5% часто це місце, де вмирає продуктивність, особливо на пулах з фрагментацією, маленьким recordsize або при високому випадковому записі. Виділення метаданих стають складнішими, вільний простір розпорошується, і навантаження, які були нормальними при 70%, починають тайм-аутитись при 92%.

Жарт №2: ZFS на 98% — як валіза в аеропорту: вона ще закривається, але всі пітніють і хтось на межі поломки застібки.

Видалення знімка не завжди одразу звільняє простір

Знищення знімків зазвичай звільняє простір швидко, але не завжди миттєво в людському розумінні:

  • Очікувані звільнення можуть відкладати фактичне повернення простору; ви можете бачити лаг у «звільненні».
  • Утримання (holds) можуть повністю блокувати видалення.
  • Клони можуть зберігати блоки посиланими навіть після спроби видалення знімка (або перешкоджати видаленню).
  • Спеціальні пристрої / метадані можуть ускладнювати те, де саме проявляється тиск (наприклад, спеціальний vdev заповнюється, тоді як основний виглядає нормально).

Практичні завдання (команди + як їх інтерпретувати)

Це реальні операційні завдання, які ви можете виконати під час спокійного дня, щоб зрозуміти свій слід знімків — або під час «гучного» дня, щоб припинити кровотечу. Команди розраховані на підказку Linux та інструменти OpenZFS.

Завдання 1: Дізнатися правду про ємність і стан пулу

cr0x@server:~$ zpool status -v
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 00:12:31 with 0 errors on Sun Dec 22 01:10:03 2025
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            sda     ONLINE       0     0     0
            sdb     ONLINE       0     0     0

errors: No known data errors

Інтерпретація: Якщо пул не здоровий, очищення знімків — неправильний перший крок. Пошкоджений vdev, resilvering або помилки контрольних сум можуть змінити симптоми продуктивності та толерантність до ризику. Результати scrub кажуть вам, чи маєте ви справу з «тиском простору», чи з «тиском цілісності даних».

cr0x@server:~$ zpool list -o name,size,alloc,free,capacity,health,fragmentation
NAME  SIZE  ALLOC   FREE  CAPACITY  HEALTH  FRAG
tank  20T   17.8T   2.2T      89%  ONLINE    43%

Інтерпретація: Ємність і фрагментація разом мають значення. 89% і 43% фрагментації на пулі з великою кількістю випадкових записів — це інша ситуація, ніж 89% і 5% фрагментації на append-only пулі.

Завдання 2: Перелік dataset з розбивкою, що враховує знімки

cr0x@server:~$ zfs list -o name,used,avail,refer,usedbysnapshots,usedbydataset,usedbychildren -r tank
NAME              USED  AVAIL  REFER  USEDSNAP  USEDDS  USEDCHILD
tank              17.8T  2.2T   256K   0B       256K    17.8T
tank/home         1.2T   2.2T   980G   220G     980G    0B
tank/vm           12.9T  2.2T   3.1T   9.8T     3.1T    0B
tank/db           3.4T   2.2T   1.9T   1.5T     1.9T    0B

Інтерпретація: Це ваш заголовок новин. tank/vm має 9.8T «used by snapshots». Це не означає, що знімки — це 9.8T копій; це означає, що стільки старих даних закріплено знімками. Живий посиланий об’єм лише 3.1T.

Завдання 3: Порахувати знімки на dataset (детектор зсуву політики збереження)

cr0x@server:~$ zfs list -H -t snapshot -o name | awk -F@ '{print $1}' | sort | uniq -c | sort -nr | head
  4320 tank/vm
   720 tank/db
   120 tank/home

Інтерпретація: 4320 знімків часто означає «кожні 10 хвилин протягом 30 днів» або «кожну хвилину протягом 3 днів», залежно від схеми найменування. Як би там не було: це багато метаданих і велика кількість закріпленої історії, якщо churn високий.

Завдання 4: Знайти найважчі знімки (за used)

cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -s used | tail -n 10
tank/vm@auto-2025-12-24-2300   48G   3.1T  Wed Dec 24 23:00 2025
tank/vm@auto-2025-12-24-2200   47G   3.1T  Wed Dec 24 22:00 2025
tank/vm@auto-2025-12-24-2100   46G   3.1T  Wed Dec 24 21:00 2025
tank/db@auto-2025-12-24-2300   18G   1.9T  Wed Dec 24 23:00 2025
tank/vm@auto-2025-12-24-2000   44G   3.1T  Wed Dec 24 20:00 2025
tank/vm@auto-2025-12-24-1900   44G   3.1T  Wed Dec 24 19:00 2025
tank/vm@auto-2025-12-24-1800   43G   3.1T  Wed Dec 24 18:00 2025
tank/vm@auto-2025-12-24-1700   42G   3.1T  Wed Dec 24 17:00 2025
tank/db@auto-2025-12-24-2200   16G   1.9T  Wed Dec 24 22:00 2025
tank/vm@auto-2025-12-24-1600   41G   3.1T  Wed Dec 24 16:00 2025

Інтерпретація: used знімка — це «простір, унікально утримуваний цим знімком». Великі числа зазвичай вказують на сильний churn між знімками. Якщо ви бачите десятки годинних дельт по 40–50 ГБ, ваша політика збереження має бути консервативною по часу, а не по кількості.

Завдання 5: Швидко побачити, які dataset — монстри churn

cr0x@server:~$ zfs list -o name,refer,usedbysnapshots,compression,recordsize,primarycache -r tank/vm
NAME      REFER  USEDSNAP  COMPRESS  RECSIZE  PRICACHE
tank/vm   3.1T   9.8T      lz4       128K     all

Інтерпретація: Компресія і recordsize впливають на динаміку churn. Неправильний вибір recordsize для VM-образів (часто краще 16K–64K залежно від випадку) може збільшити write amplification і дельти між знімками.

Завдання 6: Підтвердити, чи утримання (holds) блокують видалення

cr0x@server:~$ zfs holds tank/vm@auto-2025-12-01-0000
NAME                         TAG        TIMESTAMP
tank/vm@auto-2025-12-01-0000 backup     Wed Dec  1 00:00 2025

Інтерпретація: Hold — це явна «не видаляти» закладка. Якщо ваша задача з обрізання стверджує, що видалила знімки, але вони лишаються, утримання — головний підозрюваний.

Завдання 7: Зняти утримання (обережно) щоб дозволити обрізання

cr0x@server:~$ sudo zfs release backup tank/vm@auto-2025-12-01-0000

Інтерпретація: Це нічого не видаляє. Це знімає запобіжник. Якщо реплікаційна задача використовує утримання, щоб захистити «ще не реплікований» знімок, координуйте дії перед зняттям. Правильний робочий процес: підтвердити стан реплікації, потім release, потім destroy.

Завдання 8: Виявити клони, що залежать від знімків

cr0x@server:~$ zfs get -H -o name,value origin -r tank | grep -v -- '-'
tank/vm/dev-clone-01    tank/vm@auto-2025-12-15-0000
tank/vm/dev-clone-02    tank/vm@auto-2025-12-20-0000

Інтерпретація: Якщо існує клон, знімок-джерело не можна знищити, поки клон не буде промотований або видалений. Команди часто забувають dev/test клонів і потім дивуються, чому збереження «перестало працювати».

Завдання 9: Точно визначити, що перешкоджає видаленню знімка

cr0x@server:~$ sudo zfs destroy tank/vm@auto-2025-12-15-0000
cannot destroy 'tank/vm@auto-2025-12-15-0000': snapshot has dependent clones

Інтерпретація: ZFS каже вам правду. Ваша політика збереження тепер — проблема графа залежностей. Або видаліть клони, або промотуйте їх, або змініть політику, щоб довше зберігалися джерела.

Завдання 10: Видаляти знімки в контрольованому вікні

cr0x@server:~$ sudo zfs destroy tank/vm@auto-2025-12-01-0000

Інтерпретація: Видалення одного знімка за раз повільніше, але безпечніше, коли ви вчитеся орієнтуватися в середовищі. Коли ви довіряєте своїм правилам найменування і залежностям, можна видаляти діапазони або використовувати скрипти — але тільки після перевірки результатів.

Завдання 11: Видалити діапазон знімків за шаблоном (хірургічно, не випадково)

cr0x@server:~$ zfs list -H -t snapshot -o name -s creation | grep '^tank/vm@auto-2025-11' | head -n 5
tank/vm@auto-2025-11-01-0000
tank/vm@auto-2025-11-01-0100
tank/vm@auto-2025-11-01-0200
tank/vm@auto-2025-11-01-0300
tank/vm@auto-2025-11-01-0400

cr0x@server:~$ zfs list -H -t snapshot -o name -s creation | grep '^tank/vm@auto-2025-11' | wc -l
720

cr0x@server:~$ zfs list -H -t snapshot -o name -s creation | grep '^tank/vm@auto-2025-11' | sudo xargs -n 50 zfs destroy

Інтерпретація: Спочатку покажіть, потім порахуйте, потім видаліть. Розбивка -n 50 уникає «argument list too long». Якщо будь-який знімок у списку має утримання або клони, команда виведе помилку на тих позиціях; потрібно перевірити помилки і не вважати, що весь пакет пройшов успішно.

Завдання 12: Спостерігати відновлення простору після видалень (не панікуйте)

cr0x@server:~$ zpool list -o name,alloc,free,capacity
NAME  ALLOC   FREE  CAPACITY
tank  17.8T   2.2T      89%

cr0x@server:~$ sudo zfs destroy tank/vm@auto-2025-11-01-0000

cr0x@server:~$ zpool list -o name,alloc,free,capacity
NAME  ALLOC   FREE  CAPACITY
tank  17.7T   2.3T      88%

Інтерпретація: Повернення простору може бути поступовим. Якщо ви під тиском, видаліть стільки, щоб повернути безпечний запас (часто 15–20% вільного залежно від навантаження), а не «лише один знімок».

Завдання 13: Знайти dataset з несподіваними резерваціями (простір, який не може бути використаний)

cr0x@server:~$ zfs get -o name,property,value -r tank | egrep 'refreservation|reservation' | grep -v '0$'
tank/vm  refreservation  2T

Інтерпретація: refreservation може робити пул «виглядати більш заповненим», бо це гарантований простір. Це не проблема знімків, але часто проявляється під час інциденту із знімками, коли всі дивляться на «куди поділося вільне місце».

Завдання 14: Виміряти швидкість створення знімків і стан send/receive (середовища з реплікацією)

cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation | tail -n 5
tank/vm@auto-2025-12-24-2000  Wed Dec 24 20:00 2025
tank/vm@auto-2025-12-24-2100  Wed Dec 24 21:00 2025
tank/vm@auto-2025-12-24-2200  Wed Dec 24 22:00 2025
tank/vm@auto-2025-12-24-2300  Wed Dec 24 23:00 2025
tank/vm@auto-2025-12-25-0000  Thu Dec 25 00:00 2025

Інтерпретація: Якщо знімки з’являються, але реплікація не встигає, ви накопичуватимете «треба зберегти до реплікації» утримання (ручні або керовані інструментом), і збереження застопориться. Операційно «вибух знімків» часто — це проблема відставання реплікації у костюмі проблеми зберігання.

Швидкий план діагностики: вузькі місця та неконтрольоване зростання

Це послідовність для випадку, коли пейджер пищить. Мета — визначити, чи маєте ви справу з (a) реальним виснаженням простору, (b) збоєм у політиці збереження знімків, (c) резерваціями/тиском на спеціальних vdev, або (d) крахом продуктивності від близькості до повного та фрагментації.

Перший крок: підтвердити радіус ураження

  1. Ємність і стан пулу: перевірте zpool list і zpool status.
  2. Чи це один dataset чи кілька? перевірте zfs list -o name,usedbysnapshots,refer -r POOL.
  3. Якийсь спеціальний vdev під тиском? якщо ви використовуєте спеціальний пристрій, знайдіть його в zpool status і порівняйте симптоми пулу з навантаженням, що важить на метаданих.

Другий крок: вирішити, чи це «знімки закріпили блоки», чи «щось інше»

  1. Слід знімків: dataset з високим usedbysnapshots зазвичай підозрювані.
  2. Зсув кількості знімків: порахуйте знімки на dataset; раптові стрибки часто означають збій задачі збереження, зміну найменування або подвоєння розкладу.
  3. Резервації: перевірте refreservation/reservation; не видаляйте знімки, щоб компенсувати резервацію, яку хтось поставив місяці тому.

Третій крок: визначити, що перешкоджає очищенню

  1. Утримання: запустіть zfs holds на найстаріших знімках, які ви очікуєте видалити.
  2. Клони: перевірте origin серед нащадків; клони блокують знищення.
  3. Відставання реплікації: якщо знімки утримуються для реплікації, перевірте стан конвеєра реплікації перед зняттям утримань.

Четвертий крок: стабілізувати, а потім оптимізувати

  1. Стабілізувати: звільніть достатньо простору, щоб уникнути краю near-full. Якщо ви вище ~90%, мета — швидко й безпечно опуститися нижче цього рівня.
  2. Зупинити кровотечу: призупиніть розклади знімків або зменшіть частоту для dataset з високим churn, поки розбираєтесь.
  3. Потім налаштувати: перегляньте recordsize, розміщення навантаження, частоту/retention знімків і архітектуру реплікації.

Три міні-історії з корпоративного життя

1) Інцидент через помилкове припущення: «знімки майже безкоштовні»

Все почалося як розумний проект модернізації: перенести старий віртуалізаційний кластер на ZFS-сховище, щоб отримати контрольні суми, компресію і — улюблене слово всіх — знімки. Команда встановила годинні знімки на VM dataset і тримала 30 днів. Така політика працювала для файлового сервера роками, тож здавалася безпечною.

Помилкове припущення було не про правильність ZFS; воно стосувалося churn навантаження. Datastore віртуальних машин — не файловий сервер. Гостьові ОС роблять постійні дрібні записи, оновлюють метадані, роторують логи і перезаписують частини віртуальних дисків, які «здаються неактивними» на рівні додатка. Dataset ZFS не був великим, але змінювався повсюди й постійно.

Через два тижні пул досяг високих 80%. Потім — високих 90%. Спочатку підскочила затримка — дрібні синхронні записи застрягали через тиск на алокацію і фрагментацію. Часи завантаження VM стали дивними. Бази даних у VM почали кидати тайм-аути. Графіки сховища нагадували монітор серцебиття після еспресо.

Першою реакцією команди було «пошук великого файлу» і його видалення. Це звільнило майже нічого, бо старі блоки були закріплені сотнями годинних знімків. Тільки після виконання розбиття з урахуванням знімків візерунок став очевидним: usedbysnapshots тягнув пул.

Виправлення не було героїчним. Це був контрольований cleanup і перезавантаження політики: менше знімків на dataset з високим churn, коротша ретенція для високочастотних знімків і реплікація на іншу машину для довгострокових контрольних точок. Висновок: знімки дешево створювати, дорого тримати при churn — і навантаження визначає рахунок.

2) Оптимізація, що відкотилася: «даруємо знімки щохвилини»

Інша організація мала реальну проблему бізнесу: розробники часто відкатували тестові середовища, і інфраструктурна команда хотіла швидшого відновлення без відновлення з бекапів. Хтось запропонував знімки щохвилини для кількох dataset. На папері це було елегантно: більше знімків, менше крок між відкатами, менше часу на відновлення.

Певний час це працювало. Команда святкувала перше велике відновлення: поламана міграція схеми в staging була відкотена за секунди. Успіх створив тонкий стимул: «якщо щохвилинні знімки хороші, чому б не скрізь?» Більше dataset приєдналося до розкладу. Ніхто не хотів бути командою без страховки.

Потім відкат: накладні витрати метаданих знімків і операційна складність. Перелік знімків став повільним для сильно снапшотнутих dataset; скрипти, що припускали «кілька десятків знімків», почали таймаутитись. Відставання реплікації виросло, бо інкрементальні потоки мали проходити через більше меж знімків, і приймаюча сторона почала відставати в пікові години.

І сюрприз: частота знімків не зменшувала використання простору так, як вони очікували. При великому churn хвилинні знімки можуть фактично збільшити різноманітність утримуваних блоків: більше проміжних версій закріплюються, і менше блоків стають «повністю застарілими», доки ви не видалите набагато більший зріз історії. Дельти були маленькі, але їх було так багато, що набір закріплених блоків залишався великим.

Виправлення було контрінтуїтивним: менше знімків, але розумніші рівні. Тримайте хвилинні знімки для короткого вікна (години), годинні для середнього (дні), щоденні для довшого (тижні). І для dataset, що потребують «відкату», вони перенесли ризикові робочі навантаження (наприклад, оновлення тестової БД) в окремі dataset, щоб churn не отруював усе інше.

3) Нудна, але правильна практика, яка врятувала ситуацію: «ретенція з запобіжниками»

Ця історія майже розчаровує, бо вона не драматична. Компанія зі сфери фінансів використовувала ZFS на серверах, що хостили і домашні каталоги користувачів, і дані додатків. Їхня політика знімків була консервативною і відверто нецікавою: годинні знімки зберігалися 48 годин, щоденні — 30 днів, місячні — 12 місяців. Також були два нудні правила: знімки мали передбачувані імена, і видалення завжди передувало інвентаризаційному звіту.

Одної п’ятниці баг коміграції пошкодив стан додатка таким чином, що це було не відразу очевидно. Додаток продовжував працювати, але якість даних деградувала. До понеділка бізнес помітив проблему. Це саме та ситуація, де «просто відновити з минулої ночі» не допоможе — потрібні кілька точок у часі, щоб оповити, коли почалося пошкодження.

Інфраструктурна команда не сперечалася, чи існують знімки або чи запустився розклад. У них вже були щоденні й годинні точки, і скрипти, які могли перелічити й порівняти кандидатів на відновлення. Вони змонтували знімок, перевірили інваріанти на рівні додатка і поступово просунулися до останнього доброго стану.

Вони відновилися без заповнення пулу, без винаходу нового процесу під час інциденту і без класичного хаосу «у нас є знімки, але ми не впевнені, що в них є». Нудна частина, що спрацювала: вони також мали жорсткий guardrail по ємності — алерти на 75/80/85% з явним runbook — тож пул ніколи не підійшов близько до краю під час їхнього форенсичного відновлення.

Люди люблять купувати надійність через фічі. Вони врятували ситуацію звичками.

Поширені помилки: симптоми та виправлення

Помилка 1: Плутати «referenced» з «used» і зарано оголошувати перемогу

Симптом: Ви видаляєте великі каталоги, zfs list показує менший refer, але zpool list майже не змінюється.

Причина: Знімки утримують старі блоки. Живий dataset зменшився; алокація пулу — ні.

Виправлення: Перевірте usedbysnapshots і обріжте знімки відповідно до політики. Перевірте, що немає утримань/клонів, які блокують видалення.

Помилка 2: Сліпе обрізання знімків за шаблоном іменування, який ви не перевірили

Симптом: Задача збереження видаляє не ті знімки (або жодного), або видаляє найновіші і зберігає найстаріші.

Причина: Зміна формату іменування, зміни часових зон, кілька інструментів пишуть різні префікси, або лексикографічне сортування не відповідає часовому порядку.

Виправлення: Сортуйте за creation, а не за ім’ям; зробіть dry-run переліку перед видаленням. Віддавайте перевагу zfs list -s creation як джерелу істини.

Помилка 3: Ігнорувати клони і потім дивуватися, чому видалення не вдається

Симптом: cannot destroy ... snapshot has dependent clones

Причина: Хтось створив клон для dev/test або для форенсики і забув про нього.

Виправлення: Знайдіть клони через zfs get origin. Вирішіть: видалити клон або промотувати його, якщо він має жити самостійно, а потім переглянути політику збереження.

Помилка 4: Утримання використовуються реплікацією, але ніхто не моніторить відставання реплікації

Симптом: Кількість знімків росте; видалення тихо не вдаються; вік найстарішого знімка зростає.

Причина: Інструменти реплікації ставлять утримання до того часу, поки знімок не буде безпечно переданий; реплікація відстає і набір утримань зростає.

Виправлення: Моніторьте реплікацію наскрізь. Під час реагування на інцидент підтвердіть останній реплікований знімок перед зняттям утримань. Виправляйте конвеєр, а не боріться із симптомами.

Помилка 5: Працювати пулом занадто гарячо

Симптом: Сплески затримки, уповільнення алокації, іноді помилки схожі на ENOSPC, хоча «df показує простір».

Причина: Високе використання пулу і фрагментація спричиняють крах продуктивності, особливо при випадкових записах.

Виправлення: Відновіть запас. Встановіть операційні SLO для ємності (алерти раніше). Перегляньте політику збереження та розміщення навантаження.

Помилка 6: Обробляти metadata special vdev як магічне підвищення продуктивності

Симптом: Основний пул показує вільне місце, але система все одно не може записувати або продуктивність падає; special vdev повний.

Причина: Special vdev заповнився (метадані/дрібні блоки). Знімки й churn з дрібними файлами можуть посилити тиск на метадані.

Виправлення: Моніторьте розподіл спеціального vdev. Тримайте там запас також. Розгляньте налаштування special_small_blocks і політик знімків, і плануйте ємність для росту метаданих.

Контрольні списки / покроковий план

Покроково: побудувати політику збереження знімків, яка не з’їсть ваш пул

  1. Класифікуйте dataset за churn: VM-образи, бази даних, кеші CI, домашні каталоги, логи. Не застосовуйте один розклад до всіх.
  2. Визначте цілі відновлення: «Хочу годинний відкат на два дні» — це вимога. «Тримати все назавжди» — це бажання.
  3. Використовуйте рівневу ретенцію: коротке вікно з високою частотою + довше з низькою частотою. Так ви отримаєте гранулярність без безкінечного закріплення.
  4. Відокремте ризикові навантаження: помістіть кеші CI і тимчасові простори в окремі dataset з агресивними правилами очистки.
  5. Зробіть імена знімків передбачуваними: послідовний префікс + ISO-подібний часовий штамп. Передбачуваність запобігає багам видалення.
  6. Визначте, як обробляти holds/клони: документуйте, хто може клонувати, скільки часу клони живуть, і як захищаються джерела.
  7. Додайте запобіжники ємності: алерти на 75/80/85% і жорстка політика «зупинити створення знімків при X%» для некритичних dataset.
  8. Репетируйте відновлення: монтування знімка і відновлення файлу має бути рутиною, а не нічним мистецтвом.

Покроково: безпечно звільнити простір під час інциденту, пов’язаного зі знімками

  1. Заморозити зміни: призупиніть розклади створення знімків, якщо вони погіршують ситуацію (особливо хвилинні задачі).
  2. Знайти головних споживачів знімків: zfs list -o name,usedbysnapshots -r POOL.
  3. Виявити блокери: утримання і клони на найстаріших знімках, які ви хочете видалити.
  4. Видаляти найстаріші знімки першими: вони зазвичай фіксують найширшу історію. Уникайте видалення «свіжих точок відновлення», якщо це не потрібно.
  5. Перевірити ємність пулу: не зупиняйтесь на «було 98% стало 96%». Поверніться до безпечного запасу.
  6. Післяінцидентне виправлення: налаштуйте рівні ретенції, підберіть частоту знімків по класу dataset і вирішіть питання відставання реплікації, якщо є.

Покроково: рутинний тижневий аудит (нудна практика)

  1. Перегляньте zpool list і тенденції фрагментації.
  2. Перегляньте топ dataset за usedbysnapshots.
  3. Перевірте кількість знімків на dataset; помітьте аутлайєри.
  4. Пошукайте старі знімки з несподіваними утриманнями.
  5. Проскануйте на забуті клони і вирішіть, чи їх потрібно промотувати або видалити.

Питання та відповіді

1) Чи роблять знімки ZFS копію всього dataset?

Ні. Вони закріплюють посилання на існуючі блоки. Вплив на простір з’являється пізніше, коли блоки змінюються — старі блоки не можуть бути звільнені, поки на них посилаються знімки.

2) Чому zfs list показує величезне використання знімків у dataset, який «майже не змінювався»?

Щось змінилося більше, ніж ви думаєте. VM-образи, бази даних і навантаження з дрібними файлами можуть викликати churn блоків навіть коли дані на рівні додатка здаються стабільними. Також переконайтеся, що ви дивитесь usedbysnapshots, а не плутаєте його з refer.

3) Якщо я видалю великий каталог, коли я отримаю назад простір?

Ви отримаєте його назад, коли жоден знімок більше не посилається на ці блоки. Якщо існують знімки, які передують видаленню, блоки залишаються закріпленими, доки ці знімки не будуть знищені (або доки вони не вийдуть з-під ретенції).

4) Чому я не можу знищити знімок?

Поширені причини: у нього є залежні клони або на нього накладено утримання. Перевірте zfs holds SNAP і знайдіть клони за допомогою zfs get origin -r.

5) Чи зашкодить видалення знімків продуктивності?

Видалення великої кількості знімків може створити IO і CPU-навало, особливо на зайнятих системах, і може конкурувати з робочим навантаженням. Але альтернатива — працювати майже заповненим — часто шкодить більше. Робіть масові видалення контрольовано пачками і спостерігайте за затримками.

6) Чи частіші знімки завжди кращі?

Ні. Частіші знімки покращують гранулярність відновлення, але можуть збільшити накладні метадані і утримувати більше проміжних версій. Рівнева ретенція зазвичай краща за «щохвилинні знімки назавжди».

7) Скільки вільного місця слід тримати в пулі ZFS?

Однозначної цифри немає, але багато продакшн-команд ставлять ~80–85% як м’яку межу для змішаних навантажень, нижче для пулів з інтенсивними випадковими записами. Важливо лишити достатньо відносно сумісного вільного простору, щоб уникнути проблем з алокацією і спіралі фрагментації.

8) Чи захищають знімки від рансомвару?

Знімки можуть захистити від рансомвару, який шифрує файли — якщо атакуючий не може видалити знімки. Якщо зловмисник отримав привілеї, він також може знищити знімки. Реплікуйте знімки на окрему систему з обмеженими повноваженнями та незалежною політикою збереження, якщо хочете справжню стійкість.

9) Чому «used» знімків виглядає по-різному на різних серверах?

Відмінності можуть походити від дефолтових налаштувань властивостей, флагів функцій, компресії, recordsize і churn навантаження. Завжди порівнюйте, використовуючи явні колонки (наприклад, usedbysnapshots) і консистентні команди.

10) Чи нормально робити знімки баз даних?

Так, але з обережністю. Для crash-consistent знімків може знадобитися координація з додатком (flush/checkpoint) залежно від СУБД і очікувань відновлення. Також очікуйте вищого churn і плануйте ретенцію відповідно.

Висновок

ZFS-знімки — це суперсила, бо вони перетворюють час на операційний примітив: ви можете швидко створювати консистентні контрольні точки часто без зупинки навантажень. Підступ у тому, що час не є безкоштовним. Кожен знімок — це обіцянка пам’ятати старі блоки, і dataset з високим churn збирає ці обіцянки як відсотки.

Керуйте знімками як будь-якою іншою продакшн-фічею: вимірюйте швидкість змін, класифікуйте dataset, встановлюйте рівневу ретенцію, моніторьте ємність заздалегідь і розглядайте утримання/клони як перші класи залежностей. Зробіть це — і знімки залишаться тим, чим вони повинні бути: найшвидшим «скасувати», який ви коли-небудь використовували, без перетворення пулу на смітник.

← Попередня
Debian 13: AppArmor блокує ваш сервіс — дозвольте лише необхідне, не вимикаючи безпеку
Наступна →
MySQL vs PostgreSQL: репліки для читання — коли вони допомагають і коли брешуть

Залишити коментар