Люди, які працюють із ZFS, люблять практичні правила. Вони заспокоюють — як мітки на електричному щитку або обіцянка «пізніше впорядкувати layout датасетів». Найвідоміше з них — «правило 80% ZFS»: не дозволяйте пулу перевищувати 80% заповнення, інакше продуктивність впаде як зі скелі, і почнеться біда. У продакшні його повторюють так, ніби це закон фізики.
Правда краща й корисніша. Лінія 80% — це не забобон і не універсальний закон. Це груба межа для кількох реальних механізмів: розподілу метаслебі, фрагментації, поведінки копіювання при записі, зростання метаданих і безжальної математики «потрібна приблизно суміжна вільна область, щоб записати ефективно». Справжня зона небезпеки — не одне число; це момент, коли ваш залишковий вільний простір перестає бути корисним для вашого навантаження.
Що насправді означає «правило 80%»
«Правило 80%» — це скорочений вираз для: алокація ZFS ускладнюється по мірі заповнення пулу, і коли вона ускладнюється достатньо, все, що вас цікавить (затримки, пропускна здатність запису, часи resilver, видалення снапшотів), може деградувати нелінійно.
Ось у чому суть: нелінійно. ZFS не поступово й чемно сповільнюється, як ліфт із надмірною кількістю людей. Це більше схоже на паркування в місті, коли залишилися лише дивні, крихітні, напівзаблоковані місця. Ви все ще можете припаркуватися, але середній час пошуку місця зростає в рази.
Дві жарти, як і обіцяно, бо люди в стораджі виживають завдяки гумору й кофеїну:
Жарт №1: Правило 80% схоже на дієту: усі за неї, а потім приходить п’ятниця.
Жарт №2: Якщо хочете дізнатися, що насправді означає «копіювання при записі», заповніть пул до 95% і подивіться, як ваш застосунок перепише своє резюме.
Тож 80% — правильно?
Іноді. Для багатьох змішаних навантажень «тримати під ~80%» — це консервативно й вберігає від проблем. Але це не магічний поріг. Деякі пули працюють спокійно при 85–90%, бо навантаження переважно послідовні читання й великі послідовні записи, фрагментація контрольована, і є резерви в інших місцях (швидкий спеціальний vdev для метаданих, достатньо RAM, адекватний recordsize). Інші пули стають нещасними вже при 70–75%, бо там рандомні записи малими блоками, інтенсивна політика збереження снапшотів і купа маленьких метаслебі через вузькі vdev.
Мета не в тому, щоб поклонятися 80%. Мета — зрозуміти що робить ваш пул «ефективно повним» перш ніж показник «used» досягне 100%.
Що фактично змінюється по мірі зменшення вільного простору
На високому рівні ZFS має знайти вільні блоки для задоволення алокацій. Коли пул заповнюється, залишкові вільні блоки стають більш фрагментованими та нерівномірно розподіленими по метаслєбах. Рішення алокатора стають дорожчими та менш оптимальними, що може перетворитися на:
- Збільшення write amplification (більше вводу/виводу на одиницю логічного запису).
- Більш розсипані записи (гірше для HDD, також небажано для SSD).
- Подовження часу синхронізації груп транзакцій (TXG) — видно як стрибки затримки.
- Повільніші операції очищення (видалення снапшотів може відчуватися як штовхання піаніно вгору).
- Подовження часу resilver і scrub, особливо коли пул «гарячий» і фрагментований.
Коротка історія та факти, що пояснюють фольклор
Правила в стораджі не виникають з магії; вони з’являються після того, як багато людей обпеклися в одному й тому ж місці. Ось конкретні факти та контекст, які роблять правило 80% зрозумілим — без перетворення його на писання:
- ZFS з самого початку проектувався для копіювання при записі. Це означає, що перезаписи стають «виділити нове, потім оновити вказівники», а для цього потрібен вільний простір навіть щоб змінити існуючі дані.
- Аллокатор метаслєбів віддає перевагу регіонам з низькою фрагментацією. Коли пул заповнюється, «хороші» метаслєби витрачаються, і аллокатор дедалі частіше працює з обрізками.
- Ранні розгортання ZFS були орієнтовані на HDD. HDD карають за рандомні записи та пошуки; «урвищність» була очевидною. SSD згладжують біль, але не прибирають накладні витрати на алокацію і метадані.
- RAIDZ змінює математику. RAIDZ має паритет і поведінку зі смугоутворенням. Малоблокові рандомні записи можуть стати операціями читай-модифікуй-запиши, а фрагментований вільний простір усе ускладнює.
- Снапшоти дешеві, поки не стануть дорогими. Створення снапшоту швидке; утримання й видалення на масштабі можуть перетворити «вільний простір» на складну відповідальність.
- 128K став культурним дефолтом для recordsize. Цей дефолт чудовий для багатьох послідовних навантажень, але погано співпрацює з малими рандомними записами й churn снапшотів, якщо не налаштовувати per-dataset.
- Помилки ashift залишаються назавжди (для того vdev). Невірні припущення про вирівнювання секторів можуть марнувати простір і I/O-резерв, зменшуючи практичний запас місця.
- Спеціальні vdev змінили економіку метаданих. Переміщення метаданих (і за бажанням малих блоків) на швидкі диски може дозволити пулу бути придатним при вищому заповненні — якщо їх правильно розмірено. Якщо ні, це може стати новою точкою відмови, коли спеціальний vdev заповниться.
- «df» і «zfs list» говорять різні істини. Традиційні файлові системи дозволяють прикидатися; ZFS показує більше реальності: снапшоти, резерви й referenced vs used мають значення.
Справжня зона небезпеки: коли вільний простір перестає бути корисним
Якщо хочете одну операційну фразу замість «ніколи не перевищуйте 80%», використовуйте цю:
Зона небезпеки починається тоді, коли залишковий вільний простір пулу не може ефективно задовольнити ваш шаблон алокацій, особливо під піковим записовим навантаженням і при утриманні снапшотів.
«Used» — це не те саме, що «стрес»
Два пули можуть бути обидва на 85% використання й поводитися зовсім по-різному. Стрес залежить від:
- Фрагментації вільного простору: Чи є у вас вільні блоки великими екстентами, чи купа конфетті?
- Розміру запису й локальності: Пишете великі послідовні блоки або 4K рандомні оновлення?
- Геометрії vdev: Дзеркала поводяться інакше, ніж RAIDZ; більше vdev — більше «доріжок» для алокації.
- Churn снапшотів: Часті снапшоти + перезаписи означають, що ваші frees затримуються, а live-набір росте «тіньовими копіями».
- Навантаження на метадані: Мільйони дрібних файлів, розширені атрибути, ACL і таблиці dedup створюють метадані I/O, які не виглядають як «великі записи».
Практичне визначення «ефективно повний»
У продакшні я називаю пул «ефективно повним», коли виконується будь-яка з цих умов:
- Затримка запису застосунку стає непередбачуваною (p99 і p999 стрибки), хоча диски не насичені по сирому throughput.
- Час синхронізації TXG зростає і залишається високим при стабільному навантаженні запису.
- Видалення снапшотів зависає або займає годинами більше, ніж зазвичай.
- Оцінки часу resilver стають комічними, особливо в робочий час.
- Ви починаєте «лікувати» продуктивність перезавантаженнями — знак, що ви в запереченні й вичерпали ідеї.
Чому урвищність відчувається раптовою
Урвищність — це петля зворотного зв’язку:
- Пул заповнюється і фрагментується.
- Алокації стають більш розсипаними; записи тривають довше.
- Довші записи тримають TXG відкритими довше; накопичується більше dirty-даних.
- Більше dirty-даних означає важчу роботу синхронізації; зростає затримка синку.
- Застосунки бачать затримку й повторюють або ставлять у чергу; навантаження зростає.
Справа не в тому, що ZFS «панікує при 81%». Справа в тому, що ваше навантаження переходить ту межу, де вибір алокатора перестає бути дешевим.
Моделі навантаження, які першими натрапляють на стіну
VM і бази даних: рандомні записи на RAIDZ
Класика. Багато оновлень 8K–16K, синхронні записи й churn перезаписів. Якщо це RAIDZ, малими блоками можуть викликатися цикли читай-модифікуй-запиши. Додайте снапшоти — і ви створили машину, що виробляє фрагментацію.
Файлові шарінги зі снапшотами, частими перейменуваннями і дрібними файлами
Churn метаданих і відкладені frees. Користувачі не помічають перші 50 000 снапшотів, бо читання все ще відчуваються добре. Потім видалення, перейменування й операції по каталогах починають гальмувати, і всі звинувачують «мережу».
Бекапи та об’єктоподібне сховище з великими послідовними потоками
Це може терпіти вище заповнення, якщо навантаження переважно додаткове (append-mostly) і ви не перезаписуєте дані на місці. Але остерігайтеся: закінчення зберігання (масові видалення) може створити власну бурю.
Контейнери та CI-пайплайни
Багато дрібних файлів, короткий життєвий цикл, шари overlayfs, кеші збірки і події «видалити все». ZFS може чудово працювати тут, але при майже повних пулах постійне створення/видалення перетворює churn у проблему алокації.
Облік простору: чому «df» бреше, а ZFS — ні
ZFS дратує людей, бо відмовляється зберігати ілюзію простоти. У вас може бути 2 ТБ «вільних» в одному вигляді й одночасно — нестача місця в іншому. Зазвичай ніхто не бреше; ви просто ставите різні питання.
Ключові терміни, що мають значення
- USED: Простір, спожитий датасетом і його нащадками, включно зі снапшотами (залежно від того, де дивитесь).
- REFER: Простір, унікально посиланий цим датасетом (без урахування снапшотів).
- AVAIL: Простір, доступний з урахуванням квот/резервів і вільного місця пулу.
- ЗАПИСАНО vs фактично: Стиснення й копії змінюють значення «логічного» проти «фізичного».
Чому снапшоти роблять вільний простір призраком
Із снапшотами видалення не обов’язково звільняє блоки. Перезаписи виділяють нові блоки; старі блоки залишаються посиланнями у снапшотах. Тож ваша реакція «видалити великий файл» не дає вам стільки, скільки на ext4. Пул може виглядати так, ніби має вільний простір, але алокатор усе ще змушений працювати в незручних місцях, бо вільний простір фрагментований або нерівномірно розподілений.
Три міні-історії з корпоративного життя (з передової)
1) Інцидент через неправильне припущення: «80% безпечно, значить 79% теж»
Середнє підприємство керувало кластером NFS на ZFS для домашніх директорій і кількох build farm. Команда зберігання мала дашборд з гарною зелено-жовто-червоною смугою: зелено до 80%, жовто понад 80%, червоно понад 90%. Виглядало професійно, і всім подобалося, бо воно зменшувало суперечки кольором.
Потім пул досяг 79% використання. Все ще зелено. Того тижня в build farm різко зріс churn артефактів через вихід продукту, а в домашньому шарі була квартальна політика снапшотів. Нічого екзотичного: багато малих файлів, які створюються й перезаписуються, плюс снапшоти що години.
У вівторок helpdesk почав бачити «випадкові» помилки збірки. У середу NFS-клієнти почали зависати на операціях з метаданими: stat(), листинги каталогів, перейменування файлів. Мережна команда отримала виклик, бо «NFS повільний», і вони зробили те, що роблять мережеві команди: довели, що мережа ні в чому не винна.
До четверга команда зберігання знайшла правду: пул не був «безпечним» при 79%. Він був ефективно повним для того навантаження. Метаслєби фрагментувалися настільки, що пошуки алокатора й розсипані записи довбались по затримці. Лінія 80% не була урвищем; це було народне попередження. Їхні дашборди були зеленими, поки користувачі горіли.
Виправлення не було магією. Вони звільнили простір, спаливши старі снапшоти, перемістили артефакти збірки в датасет з налаштованим recordsize і стисненням і — найважливіше — змінили алертинг, щоб відстежувати не лише відсоток використання, а ще й затримку запису, поведінку TXG і приріст простору снапшотів. Нова «зелена» зона ґрунтувалася на поведінці, а не на цифрі.
2) Оптимізація, що зіграла злий жарт: «Задвинемо recordsize і все стиснемо»
Інша компанія використовувала ZFS для віртуалізації. У них були SSD, багато RAM і впевненість — завжди небезпечний інгредієнт. Хтось помітив, що дефолт recordsize — 128K, і вирішив «більше — краще», піднявши його до 1M на VM-датасеті. Вони також ввімкнули агресивне стиснення всюди, бо це гарно виглядало в квартальному звіті зі зберігання.
Спочатку було нормально. Бекапи стали менші. Показник «used» пулу виглядав краще. Потім, по мірі зростання використання, затримка рандомних записів почала стрибати. VM-навантаження, що робило дрібні оновлення, тепер зачіпали величезні рекорди, посилюючи записи й роботу з метаданими. Стиснення додало навантаження на CPU саме у той момент, коли система мала приймати швидкі рішення алокації й встигати за синком.
Найгірше: їхній моніторинг в основному відстежував throughput і відсоток використання. Throughput виглядав нормально. Відсоток використання був нижче 80%. Тим часом гіпервізори таймаутилися по операціях зі зберігання в пікові години. Діловий досвід був «платформа нестабільна», а це найдорожчий тип багу продуктивності.
Вони відкотилися: диски VM перемістили в датасети з адекватним recordsize (а для zvol — правильним volblocksize), стиснення залишили, але під рівень CPU, і розділили навантаження по датасетах замість одного-розміру-на-всіх. Урок не в тому, що «стиснення погане» чи «великий recordsize поганий». Урок: оптимізації, які допомагають звітам по ємності, можуть нашкодити поведінці алокації при заповнених пулах.
3) Нудна, але правильна практика, що врятувала день: резервації, запас і відпрацьоване прибирання
Фінансова компанія використовувала ZFS для пайплайна лог-аналітики й внутрішніх файлових сервісів. Без героїки: багато додаткових записів, періодичні компакти й снапшоти для швидкого відкату. Керівник зберігання не любив героїчні відновлення, тож зробив нудний план: тримати 20–25% запасу, застосувати квоти і створити «break glass» датасет з резервованим простором для аварій.
Це було непопулярно. Команди ненавидять квоти так само, як коти ванни. Але погодилися після кількох зустрічей і спокійних пояснень про копіювання при записі і утримання снапшотів. Вони також зробили runbook очищення: які снапшоти видаляти першими, які датасети можна очищати і що треба зберегти. Це тестували щоквартально, як протипожежну вправу.
Одного року безконтрольний лог-цикл почав генерувати величезні дані. У менш дисциплінованому середовищі пул досяг б 95% і перетворився б на карнавал затримок. Тут алерти спрацювали рано (тренд простору + затримка), квоти обмежили зону ураження, а резервований «break glass» простір забезпечив можливість запису критичних сервісів під час прибирання. Вони виконали runbook без імпровізацій: видалили некритичні снапшоти, призупинили проблемний пайплайн, перевірили цілісність, потім відновили роботу.
Нічого героїчного не сталося. Ось у чому суть. Нудна практика не зробила гарної історії на загальних зборах, але запобігла поганої історії в соцмережах.
Практичні завдання: команди, виводи та як їх читати
Нижче — практичні завдання, які я реально використовую, коли пул «таємничо повільний» або наближається до зони небезпеки. Команди показані так, ніби виконуються на типовому Linux-хості з OpenZFS. Додано інтерпретації — бо сирий вивід без сенсу — це просто декорація.
Завдання 1: Перевірити ємність і стан пулу (базовий рівень)
cr0x@server:~$ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 54.5T 44.1T 10.4T - - 38% 80% 1.00x ONLINE -
Інтерпретація: CAP на рівні 80% не обов’язково погано, але це момент, коли варто почати приділяти увагу. FRAG — індикатор, а не вирок. FRAG 38% може бути як нормальним, так і болючим, залежно від навантаження.
Завдання 2: Отримати деталі vdev-структури та знайти очевидне вузьке місце
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 07:12:33 with 0 errors on Sun Dec 22 02:10:14 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
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
errors: No known data errors
Інтерпретація: Стан — добре. Це не означає, що продуктивність добра. Якщо один диск має високі READ/WRITE помилки або періодично відпадає, ви побачите це тут — майже повні пули підсилюють біль від маргінального обладнання.
Завдання 3: Визначити, що споживає простір (топ датасети)
cr0x@server:~$ zfs list -o name,used,refer,avail,compressratio,mountpoint -S used | head -n 12
NAME USED REFER AVAIL COMPRESSRATIO MOUNTPOINT
tank 44.1T 128K 10.4T 1.35x /tank
tank/vm 18.7T 18.2T 10.4T 1.12x /tank/vm
tank/home 12.4T 9.1T 10.4T 1.61x /tank/home
tank/backup 9.8T 9.7T 10.4T 1.05x /tank/backup
tank/containers 2.1T 1.9T 10.4T 1.48x /tank/containers
Інтерпретація: USED включає снапшоти залежно від ієрархії датасетів; REFER — дані live. Великий розрив між USED і REFER часто означає, що снапшоти утримують багато старих блоків.
Завдання 4: Оцінити вплив снапшотів на простір
cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -S used | head -n 10
NAME USED REFER CREATION
tank/home@hourly-2025-12-24-2300 420G 9.0T Wed Dec 24 23:00 2025
tank/home@hourly-2025-12-24-2200 390G 8.9T Wed Dec 24 22:00 2025
tank/vm@daily-2025-12-24 210G 18.1T Wed Dec 24 01:00 2025
tank/home@hourly-2025-12-24-2100 180G 8.8T Wed Dec 24 21:00 2025
Інтерпретація: USED снапшота — виключний простір, утримуваний цим снапшотом. Якщо кілька снапшотів великі, ймовірно у вас сильний churn перезаписів (VM, БД, кеші CI) у цьому датасеті.
Завдання 5: Знайти резервації й квоти, які роблять AVAIL дивним
cr0x@server:~$ zfs get -o name,property,value,source quota,refquota,reservation,refreservation tank/home tank/vm
NAME PROPERTY VALUE SOURCE
tank/home quota none default
tank/home refquota none default
tank/home reservation none default
tank/home refreservation none default
tank/vm quota 20T local
tank/vm refquota none default
tank/vm reservation 2T local
tank/vm refreservation none default
Інтерпретація: Резерви відрізають простір навіть коли пул щільний. Гарно для захисту критичних навантажень, заплутує, якщо ви забули, що їх встановили.
Завдання 6: Перевірити фрагментацію пулу й класи алокації
cr0x@server:~$ zdb -L -bbbs tank | head -n 30
Traversing all blocks to verify metadata...
Metaslabs:
tank: 256 metaslabs, 38% fragmented, 80% capacity
...
Summary:
blocks = 123456789
alloc = 44.1T
free = 10.4T
Інтерпретація: Фрагментація тут — на рівні пулу й груба, але корелює з болем алокатора. Підвищення FRAG разом зі зростанням затримки запису — ваша сирена «зона небезпеки».
Завдання 7: Переглянути властивості датасету, що впливають на поведінку при заповненні
cr0x@server:~$ zfs get -o name,property,value,source recordsize,compression,atime,sync,logbias,primarycache,secondarycache tank/vm
NAME PROPERTY VALUE SOURCE
tank/vm recordsize 128K default
tank/vm compression lz4 local
tank/vm atime off local
tank/vm sync standard default
tank/vm logbias latency local
tank/vm primarycache all default
tank/vm secondarycache all default
Інтерпретація: Для VM-датасетів важливі recordsize і поведінка sync. Ближчі до повного пули карають sync-важкі рандомні записи; logbias і правильно розгорнутий SLOG можуть допомогти, але вони не вирішать фрагментацію.
Завдання 8: Перевірити volblocksize для zvol (поширена проблема VM)
cr0x@server:~$ zfs get -o name,property,value,source volblocksize tank/vm/zvol0
NAME PROPERTY VALUE SOURCE
tank/vm/zvol0 volblocksize 8K local
Інтерпретація: Розумний volblocksize може зменшити write amplification. Невідповідність (наприклад 128K для 8K навантаження або 4K для великих послідовних записів) може змусити «майже повний» пул відчуватися гірше раніше.
Завдання 9: Стежити за реальними затримками та IOPS по vdev у реальному часі
cr0x@server:~$ zpool iostat -v tank 1 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 44.1T 10.4T 820 1600 110M 95.2M
raidz2-0 44.1T 10.4T 820 1600 110M 95.2M
sda - - 120 250 17.0M 15.8M
sdb - - 118 260 16.5M 16.2M
sdc - - 130 245 17.2M 15.4M
sdd - - 112 270 16.1M 16.8M
sde - - 160 300 22.0M 18.5M
sdf - - 180 275 21.2M 17.0M
Інтерпретація: Шукайте диск-аутлайєр, що виконує менше роботи (або показує помилки). Також зверніть увагу: пропускна здатність може виглядати нормально, тоді як затримка — ні. Використовуйте iostat і метрики застосунку, а не лише throughput.
Завдання 10: Перевірити стан ARC і чи кешується те, що важливо
cr0x@server:~$ arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:00:01 890 120 13 10 1 40 4 70 8 96G 112G
12:00:02 910 140 15 15 2 50 5 75 8 96G 112G
12:00:03 870 110 12 8 1 38 4 64 7 96G 112G
Інтерпретація: Промахи ARC не завжди погані, але якщо метадані промахи зростають під час операцій по каталогах, близькі до повного пули страждають більше, бо кожна операція метаданих викликає додатковий розрізаний I/O.
Завдання 11: Подивитися, чи домінують sync-записи (і чи допомагає SLOG)
cr0x@server:~$ cat /proc/spl/kstat/zfs/zil
8 1 0x01 107 8880 1234567890 987654321
name type data
zil_commit_count 4 152340
zil_commit_writer_count 4 152338
zil_itx_count 4 9832451
zil_itx_indirect_count 4 0
Інтерпретація: Висока активність commit вказує на sync-важкі навантаження. Якщо ви близькі до заповнення і маєте багато sync-записів, ви це відчуєте. SLOG може зменшити затримку sync-записів, але не вилікує фрагментацію алокації або write amplification від снапшотів.
Завдання 12: Підтвердити ashift (вплив на ємність і вирівнювання I/O)
cr0x@server:~$ zdb -C tank | grep -E "ashift|vdev_tree" -n | head
109: vdev_tree:
174: ashift: 12
231: ashift: 12
Інтерпретація: ashift=12 (4K) — поширене. Якщо ви випадково побудували з надто малим ashift для дисків з 4K-native, ви отримаєте неефективність по ємності й I/O, що зменшить реальний запас місця.
Завдання 13: Виміряти «біль від видалення» (безпечно)
cr0x@server:~$ time zfs destroy -nvp tank/home@hourly-2025-12-24-2100
would destroy tank/home@hourly-2025-12-24-2100
would reclaim 180G
Інтерпретація: Dry-run показує приблизний вилучений простір. Якщо видалення на практиці тривають вічно, це часто знак глибокої фрагментації і/або великого churn метаданих. Плануйте видалення в непікові періоди й уникайте масових destroy під час піку записів.
Завдання 14: Виявити кандидати на special vdev для малих блоків (метадані/дрібні блоки)
cr0x@server:~$ zfs get -o name,property,value,source special_small_blocks tank/home tank/containers
NAME PROPERTY VALUE SOURCE
tank/home special_small_blocks 0 default
tank/containers special_small_blocks 0 default
Інтерпретація: Якщо у вас є special vdev і ви дозволите малим блокам потрапляти туди, ви зменшите рандомний I/O на HDD-vdev. Але це проектне рішення, а не лейкопластир: якщо недо-розмірити special vdev, створите новий режим відмови, коли він заповниться.
Швидкий план діагностики (що перевірити спочатку, потім)
Коли кажуть «ZFS повільний» і пул наближається до заповнення, вам потрібна відтворювана послідовність, яка знайде вузьке місце до того, як зустрічі помножаться.
Спочатку: підтвердити, чи це тиск ємності чи щось інше
- CAP і FRAG пулу: CAP > ~80%? FRAG зростає з часом?
- Затримка запису в застосунку: Чи бачите стрибки p99, що корелюють із навантаженням запису або операціями зі снапшотами?
- Помилки/дефектні пристрої: Є помилки дисків, повільні пристрої або тривалі resilver?
cr0x@server:~$ zpool list -o name,size,alloc,free,frag,cap,health
NAME SIZE ALLOC FREE FRAG CAP HEALTH
tank 54.5T 44.1T 10.4T 38% 80% ONLINE
По-друге: визначити, чи обмежені ви IOPS, пропускною здатністю, sync або CPU
- IOPS і bandwidth по vdev:
zpool iostat -v 1під час вікна скарг. - Затримка дисків: Використовуйте інструменти ОС для перегляду await/service times; майже повний пул може виглядати як «рандомний I/O усюди».
- Sync-тиск: NFS, бази даних і гіпервізори можуть форсувати sync-записи. Підтвердіть через активність ZIL і політики
syncдатасетів. - CPU: Стиснення й контрольні суми зазвичай того варті, поки коробка не вичерпає CPU під час TXG sync.
cr0x@server:~$ iostat -x 1 3
avg-cpu: %user %nice %system %iowait %steal %idle
12.30 0.00 6.10 22.40 0.00 59.20
Device r/s w/s rkB/s wkB/s await svctm %util
sda 21.0 240.0 1800 16400 28.1 2.8 73.4
sdb 18.0 255.0 1600 17100 31.5 2.9 79.2
Інтерпретація: Високий await і %util означають, що диски є обмежувачем. Фрагментація, близька до повного, має тенденцію штовхати рандомний I/O, підвищуючи await.
По-третє: визначити датасет або поведінку, що створює тиск
- Які датасети ростуть найшвидше?
zfs list -o used,referі списки снапшотів. - Які снапшоти великі? Сортуйте снапшоти за USED.
- Чи одне навантаження виконує churn перезаписів? VM, кеші CI, БД.
cr0x@server:~$ zfs list -t snapshot -o name,used -S used | head
NAME USED
tank/home@hourly-2025-12-24-2300 420G
tank/home@hourly-2025-12-24-2200 390G
tank/vm@daily-2025-12-24 210G
Типові помилки, специфічні симптоми та виправлення
Помилка 1: Вважати 80% жорсткою межею замість спостереження за поведінкою
Симптом: Пул «лише» 75–80% використання, але стрибки затримки запису і затримки при видаленні.
Виправлення: Додайте алертинг на затримку запису, час синку TXG (через системні метрики) і швидкість росту снапшотів. Тримайте запас відповідно до спостережуваного навантаження. Якщо ваш пул стає нещасним при 75%, ваше правило — 75%.
Помилка 2: Мати політику снапшотів, що росте без плану видалення
Симптом: «Ми видалили 2 ТБ, але повернулося лише 50 ГБ.» USED снапшотів великий; видалення не звільняє простір швидко.
Виправлення: Проведіть аудит утримання снапшотів по датасетах, встановіть ліміти, видаляйте найстаріші в непіковий час. Розгляньте розділення шумних навантажень в окремий датасет з власним графіком снапшотів.
Помилка 3: Міксувати несумісні навантаження в одному датасеті
Симптом: Налаштування для одного навантаження ламає інше; вибір recordsize/compression — як компроміс.
Виправлення: Розділіть навантаження по датасетах: VM, бекапи, домашні каталоги, контейнери. Налаштовуйте для кожного (recordsize/volblocksize, compression, atime, logbias).
Помилка 4: Надмірна оптимізація заради звітів про ємність
Симптом: Чудові коефіцієнти стиснення, жахлива затримка під навантаженням запису.
Виправлення: Тримайте стиснення розумним (lz4 — типовий «безкоштовний виграш»), але вимірюйте CPU-запас. Не збільшуйте recordsize для рандомних-записів.
Помилка 5: Вважати, що SLOG вирішує проблеми «майже повного» пулу
Симптом: Додали швидкий SLOG; затримка рандомних записів все одно жахлива; видалення снапшотів повільні.
Виправлення: SLOG допомагає затримкам sync-записів; він не лікує фрагментацію, навантаження на метадані чи витрати на пошуки алокації. Зосередьтесь на запасі місця й розподілі датасетів.
Помилка 6: Використовувати RAIDZ для IOPS-важких VM без достатньої ширини/кількості vdev
Симптом: Прийнятна продуктивність при 50% використання; болісна при 75%; scrubs/resilvers руйнують затримку.
Виправлення: Дзеркала (більше vdev) часто дають кращі дрібно-рандомні IOPS. Якщо лишаєте RAIDZ, плануйте більше vdev, розгляньте special vdev для метаданих і тримайте більше вільного простору.
Помилка 7: Ігнорувати динаміку відновлення/ресайлера
Симптом: Заміна диска займає вічність; продуктивність під час resilver катастрофічна.
Виправлення: Тримайте запас місця, регулярні scrubs і плануйте важкі роботи навколо обслуговування. Близькі до повного пули роблять resilver повільнішим через гірші патерни алокації й вільного простору.
Контрольні списки / покроковий план
Крок за кроком: вирішіть ваш реальний цільовий запас
- Виміряйте «норму»: Запишіть p95/p99 затримки запису, поведінку TXG (опосередковано через стрибки затримки) і базовий час scrub при 50–60% використанні.
- Виміряйте при вищому завантаженні: По мірі проходження 70%, 75%, 80% порівнюйте ці метрики щотижня.
- Знайдіть «коліно»: Точку, де варіативність затримки й операційні задачі (видалення снапшотів, scrub) деградують швидше, ніж росте ємність.
- Встановіть політику: Ваше «правило» — це те місце, де ваші навантаження лишаються нудними. Для деяких пулів це 80%. Для інших — 70%. Для append-only бекапів можна тиснути вище з ретельним моніторингом і контролем утримання.
Крок за кроком: екстрене відновлення вільного простору без хаосу
- Зупиніть кровотечу: Знайдіть найбільшого записувача і призупиніть його, якщо можливо (CI cache, лог-луп, runaway backup job).
- Видаляйте цілеспрямовано: Віддавайте перевагу видаленню снапшотів, що повернуть найбільше місця (але не робіть масових видалень у піковий час).
- Захистіть критичні датасети: Переконайтеся, що вони мають резервації або квоти, щоб одна команда не могла виснажити всіх.
- Перевірте після відновлення: Підтвердіть вільний простір пулу і стабілізацію затримок; заплануйте scrub, якщо були проблеми з обладнанням.
Крок за кроком: зробити «майже повний» менш страшним надовго
- Розділіть навантаження по датасетах і налаштуйте їх (recordsize/volblocksize, compression, atime, logbias).
- Перегляньте дизайн vdev (дзеркала проти RAIDZ, кількість vdev, розмір special vdev якщо використовується).
- Впровадьте алертинг на тренди (швидкість росту простору + затримка), а не лише пороги.
- Практикуйте прибирання (політика утримання снапшотів, аварійні вправи з відновлення простору).
Питання та відповіді
1) Чи реальне правило 80% у ZFS?
Воно реальне як попередження, а не як універсальний поріг. Багато пулів помітно ускладнюють алокацію по мірі проходження ~80%, але фактичне «коліно» залежить від навантаження, дизайну vdev і фрагментації.
2) Чому продуктивність так деградує при майже повному пулі?
Бо ZFS має виділяти нові блоки для записів (копіювання при записі), а зменшення вільного простору робить його більш фрагментованим і нерівномірно розподіленим. Аллокатор працює важче і робить менш оптимальні розміщення, що збільшує I/O і затримки.
3) Чи SSD-пули ігнорують правило 80%?
SSD маскують частину симптомів (штраф за пошук), але не усувають накладні витрати алокації, churn метаданих або вплив снапшотів. Також SSD мають власні урвищності продуктивності, коли внутрішній вільний простір (overprovisioning) скорочується.
4) Чи FRAG ZFS — надійний індикатор?
Він корисний, але недостатній. Помірний FRAG може бути нормальним для послідовних навантажень і болючим для рандомних-записів. Використовуйте FRAG разом із метриками затримки й розумінням навантаження.
5) Чи більше RAM виправить поведінку при майже повному пулі?
Більше ARC допомагає читанням і кешуванню метаданих і може зменшити частину I/O. Але воно не зробить фрагментований простір суміжним і не запобіжить болю алокатора під час важких записів. Розглядайте RAM як множник, а не як панацею.
6) Чи SLOG дозволяє працювати пулу щільніше?
SLOG може покращити затримку sync-записів для навантажень типу NFS або БД з fsync. Він не вирішує загальну неефективність алокації або write amplification через снапшоти. Він може допомогти пережити ситуацію, але не порушити закони геометрії.
7) Який найшвидший спосіб безпечно звільнити місце?
Зупиніть або обмежте найбільшого записувача, потім відновіть простір там, де він дійсно відновлюється — часто це видалення снапшотів з високим USED. Використовуйте dry-run destroy, щоб оцінити обсяг відновлення, і уникайте масових руйнівних операцій у пікові періоди.
8) Чи можна дефрагментувати пул ZFS?
Не в традиційному сенсі «запустити defrag». Ви можете зменшити фрагментацію з часом, перезаписавши дані (send/receive на новий пул або реплікація на свіжі vdev) і тримати запас простору, щоб алокатор міг робити хороші вибори.
9) Чому після видалення файлів простір не звільнився?
Тому що снапшоти можуть і далі посилатися на старі блоки. Видалення живого файлу видаляє одну посилання, але снапшоти зберігають інші. Простір звільняється, коли останнє посилання зникає — часто потрібно видалити снапшоти.
10) Яку цільову заповненість обрати?
Обирайте найвищу заповненість, яка тримає вашу систему в «нудному» стані під піком навантаження. Для багатьох загальних пулів це 70–80%. Для churn-важких VM/DB робочих навантажень безпечніше нижче. Для append-only бекапів можна тиснути вище з ретельним моніторингом і контролем ретеншену.
Висновок
Правило 80% у ZFS — це не ні міф, ні євангеліє. Це стара рана, перетворена на лозунг. Справжня інженерна правда в тому, що ZFS потребує корисного вільного простору, щоб робити алокації copy-on-write ефективно, а «корисний» залежить від фрагментації, доступності метаслєбів, патернів запису навантаження і churn снапшотів.
Якщо ви керуєте продакшн-зберіганням, виграшний хід — не сперечатись про 80%. Визначте зону небезпеки вашого пулу за поведінкою: варіативність затримок, динаміка відновлення снапшотів, вплив scrub/resilver і тренди росту. Тримайте достатній запас, щоб робити алокацію простою, дотримуйтеся нудних політик (квоти, резервації, ретеншен) — і ви менше часу витрачатимете на переговори з файловою системою, яка вичерпала хороші варіанти.