При 92% заповнення ZFS ще чемно посміхається. При 98% починає відповідати листами «згідно з моїм останнім запитом на виділення». При 100% вона не торгується: ваше «рутинне» перейменування перетворюється на інцидент в продакшені, і раптом усі дізнаються, що означає ENOSPC.
Це польовий довідник для неприємного моменту, коли пул ZFS вичерпує простір (або простір, який ZFS фактично може використовувати), а також дисциплінований шлях назад до стабільного запасу вільного місця. Він написаний для людей, які не мають часу милуватися елегантністю copy-on-write, поки пищить Pager.
Що ламається першим: ланцюг відмов при заповненні ZFS
«Pool full» — це не один стан. Це каскад обмежень, які по-різному б’ють по навантаженнях. ZFS потребує не лише байтів для ваших даних; їй потрібен робочий простір для метаданих, обліку алокацій, переписів copy-on-write і комітів транзакційної групи (TXG). Коли пул наближається до повного, вибір алокатора погіршується, фрагментація зростає, і затримки починають поводитися так, ніби вони намагаються вам щось сказати.
1) Перше, що ви відчуєте: затримки, а не обов’язково помилки
Коли вільного місця мало, у ZFS менше суміжних ділянок для алокації. Для записів це означає більше пошуків metaslab, більше фрагментації та більш розкидані I/O. Навіть якщо пул не «100%», ефект на продуктивність реальний. Для багатьох пулів критична точка починається приблизно на 80–90% залежно від recordsize, робочого навантаження та геометрії vdev. Це не забобон; це фізика алокатора та штрафи за пошук, упаковані в шар зберігання.
2) Далі додаток починає «таємно» падати
Додатки часто падають побічно:
- Бази даних можуть зависати на fsync або падати, коли не можуть створити тимчасові файли, WAL-сегменти чи нові екстенти tablespace.
- Контейнери не стартують, бо overlay-шари не можуть записати, логи не додаються або рантайм не може створити стан під
/var/lib. - Системні служби падають, бо не можуть записати pidfile, journald не може зберегти дані, або менеджер пакетів не може розпакувати файли.
3) Видалення файлів не завжди звільняє простір (і це жорстоко)
Снепшоти ZFS зберігають посилання на блоки. Якщо ви видалили каталог на 200 ГБ, але снепшоти все ще посилаються на ці блоки, використання пулу не зменшиться. В інцидентах «pool full» це момент, коли команди починають звинувачувати ZFS. ZFS невинна; вона просто послідовна.
4) Справжні гострі кути: метадані, спеціальні vdev та резервації
Деякі інциденти «pool full» фактично є інцидентами «пул має місце, але ви не можете його використати»:
- Резервації (
reservation,refreservation) можуть відгородити простір, тож ваші видалення не допомагають датасету, який вам потрібен. - Квоти (
quota,refquota) можуть обмежити датасет так, що він отримує ENOSPC, навіть коли пул має вільне місце. - Спеціальний vdev повний (якщо ви його використовуєте) може спричинити помилки алокації метаданих, навіть коли основні vdev мають запас.
- Slop space (зарезервований пулом простір) може блокувати алокації, коли ви близькі до повного — це захисна функція, яку ви будете проклинати, поки вона не врятує вас.
5) Чому «просто додати диск» не завжди дає миттєве полегшення
Розширення ємності може допомогти, але воно не відкотить фрагментацію, не виправить повний спеціальний vdev і не видалить посилання снепшотів. Також, активність по ресильверингу або розширенню додає навантаження в найгірший момент. Ви додаєте ємність, щоб вижити; вам все одно потрібне прибирання і політика, щоб відновитися.
Одна перефразована ідея від Werner Vogels (reliability/ops): «Все ламається постійно; проектуйте та експлуатуйте, припускаючи це». Це стосується заповнення сховища більше, ніж комусь хотілося б визнати.
Цікаві факти та історія (те, що змінює рішення)
- ZFS народився в Sun в середині 2000-х з copy-on-write і end-to-end контрольними сумами як основними ідеями, а не доповненнями.
- «Снепшоти дешеві» — це правда — поки пул не заповниться і «дешево» не стане «чому ніхто їх не чистить».
- ZFS використовує транзакційну модель (TXG). Ваші записи не «завершені» так, як багато хто припускає, доки TXG не закомітиться; тиск там проявляється як затримка синхронних операцій.
- Облік простору складний:
USED,REFER,USEDDS, використання снепшотів і резервації кажуть різні істини. - Правило «80%» не придумав ZFS, але ZFS робить наслідки високого заповнення більш помітними через різку деградацію поведінки алокатора.
- Спеціальні vdev (популярні в OpenZFS) можуть прискорити метадані та малі блоки, але вводять новий режим відмови «повний», якщо їх неправильно розмірити.
- Recordsize і volblocksize впливають на фрагментацію та придатність вільного простору. Великі блоки можуть бути ефективними — поки не знайдуться місця для них.
- Стиснення може відтермінувати кризу, але також може приховати зростання, поки ви не перетнете поріг і кожен запис не стане боротьбою за простір.
- Copy-on-write означає, що «перезапис» потребує вільного простору. Вичерпання вільного простору може зламати навантаження, які думають, що «просто оновлюють на місці».
Жарт #1: Пул ZFS на 99% — як переговорна зайнята «поспіль» увесь день: технічно доступна, практично непридатна.
Швидкий план діагностики (перший / другий / третій)
Якщо у вас є лише п’ять хвилин, поки у Slack з’явиться VP, зробіть це. Мета — визначити, яке з наступних є вашим вузьким місцем: ємність пулу, квота/резервація датасету, снепшоти або обмеження спеціального vdev/метаданих.
Перший крок: підтвердьте реальне обмеження
- Чи дійсно пул заповнений? Перевірте capacity і health через
zpool list. - Чи обмежений датасет? Перевірте quota/refquota для ураженого датасету.
- Чи «залип» простір у снепшотах? Подивіться на використання снепшотів і недавню політику створення снепшотів.
- Чи резерви скуповують простір? Перевірте аномалії
refreservationіreservation.
Другий крок: швидко знайдіть найбільшого споживача
- Розбиття по датасетах: знайдіть, який датасет споживає пул.
- Розбиття по снепшотах: знайдіть набір снепшотів, що «приклеює» найбільше простору.
- Перспектива процесів: знайдіть, яке навантаження зараз пише і падає.
Третій крок: оберіть найменш ризикову негайну дію
- Негайний запобіжник: зупиніть записувач (паузуйте прийом даних, вимкніть шалену логіку, зупиніть некеровані роботи).
- Малоризикове звільнення: видаліть відомо тимчасові дані без вимог до збереження у снепшотах; обріжте старі снепшоти, якщо політика дозволяє.
- Структурне виправлення: додайте ємність, відрегулюйте квоти/резервації або виправте розмір спеціального vdev — потім нормалізуйте політику снепшотів.
Не починайте з «rm -rf» у випадкових шляхах. Ви лише створите другий інцидент: «ми видалили не те і ще не звільнили простір».
Практичні кроки відновлення (команди, вивід, рішення)
Це перевірені в полі завдання, які ви можете виконати під час інциденту. Кожне завдання включає команду, реалістичний вивід, що це означає, та рішення. Виконуйте їх послідовно, якщо не впевнені. Перескакуйте, якщо вже знаєте природу проблеми.
Завдання 1: Підтвердити ємність та стан пулу
cr0x@server:~$ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 27.2T 26.6T 640G - - 72% 97% 1.00x ONLINE -
Значення: Пул tank заповнений на 97% і сильно фрагментований. Ви в зоні ризику.
Рішення: Ставте це як інцидент у процесі. Зупиніть непотрібні записувачі. Плануйте звільнення місця та/або додавання ємності.
Завдання 2: Перевірити помилки пулу та повільні пристрої
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
status: One or more devices has experienced an unrecoverable error.
action: Determine if the device needs to be replaced, and clear the errors
scan: scrub repaired 0B in 12:31:44 with 0 errors on Sun Dec 22 03:11:08 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 2 0 0
sdd ONLINE 0 1 0
errors: Permanent errors have been detected in the following files:
tank/data/postgres/base/16384/2609
Значення: Є помилки пристроїв і файл з корупцією, на який є посилання. Це окремо від «pool full», але може виявитися під навантаженням.
Рішення: Не починайте агресивне прибирання, поки не заснапшотите критичні датасети (якщо можливо) та не сплануєте ремонт дисків. Якщо пул занадто повний для створення снепшоту, спочатку безпечно звільніть трохи місця, а потім знімайте снепшоти.
Завдання 3: Виявити, які датасети споживають пул
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint -S used tank
NAME USED AVAIL REFER MOUNTPOINT
tank 26.6T 512G 192K /tank
tank/data 19.8T 512G 19.8T /tank/data
tank/backups 4.9T 512G 3.1T /tank/backups
tank/vm 1.6T 512G 1.6T /tank/vm
tank/home 310G 512G 310G /tank/home
Значення: Найбільший споживач — tank/data, далі tank/backups.
Рішення: Сфокусуйтеся на найбільших датасетах першочергово. Звільнення 50 ГБ у 27 ТБ пулі може купити хвилини, а не стабільність.
Завдання 4: Перевірити, чи снепшоти «приклеюють» простір
cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -S used tank/data | head
NAME USED REFER CREATION
tank/data@autosnap_2025-12-26_0000 620G 19.8T Fri Dec 26 00:00 2025
tank/data@autosnap_2025-12-25_0000 410G 19.6T Thu Dec 25 00:00 2025
tank/data@autosnap_2025-12-24_0000 395G 19.5T Wed Dec 24 00:00 2025
tank/data@autosnap_2025-12-23_0000 380G 19.2T Tue Dec 23 00:00
Значення: Снепшоти споживають сотні ГБ у вигляді «унікальних блоків» (стовпець USED). Видалення в tank/data не звільнить ці блоки, доки снепшоти не знищені.
Рішення: Якщо снепшоти не потрібні для відповідності чи відновлення, обріжте їх. Якщо потрібні — спочатку додайте ємність або перемістіть дані поза пулом.
Завдання 5: Швидко знайти найбільших споживачів снепшотів у пулі
cr0x@server:~$ zfs list -t snapshot -o name,used -S used tank | head -n 10
NAME USED
tank/backups@weekly_2025-12-22 1.2T
tank/data@autosnap_2025-12-26_0000 620G
tank/data@autosnap_2025-12-25_0000 410G
tank/vm@hourly_2025-12-26_0900 210G
tank/vm@hourly_2025-12-26_0800 205G
tank/home@daily_2025-12-26 18.4G
tank/home@daily_2025-12-25 17.9G
Значення: Один бекап-снепшот з’їдає 1.2 ТБ; ймовірно, це ретеншн, що вийшов з-під контролю, або датасет бекапів, який змінюється занадто багато.
Рішення: Першочергово цільте по найбільш впливовим снепшотам, але перевіряйте їхню безпеку для видалення (політика відновлення, правовий блок тощо).
Завдання 6: Перевірити квоти і refquota на проблемному датасеті
cr0x@server:~$ zfs get -o name,property,value,source quota,refquota tank/data
NAME PROPERTY VALUE SOURCE
tank/data quota none default
tank/data refquota 20T local
Значення: tank/data обмежений на 20 ТБ за referenced usage. Воно може отримати ENOSPC, навіть якщо пул має вільне місце.
Рішення: Якщо саме цей датасет падає, розгляньте тимчасове підвищення refquota — після того, як підтвердите, що це не залишить без місця інші критичні датасети.
Завдання 7: Перевірити reservation і refreservation (холдинг простору)
cr0x@server:~$ zfs get -o name,property,value,source reservation,refreservation -r tank | egrep -v 'none|0B|default'
tank/vm refreservation 2T local
tank/db reservation 1T local
Значення: Два датасети резервують 3 ТБ. Цей простір ефективно недоступний для інших датасетів.
Рішення: В аварійному випадку зменшіть або видаліть резервації, якщо ви готові ризикувати (резервації існують не дарма). Задокументуйте зміни та відновіть їх пізніше.
Завдання 8: Підтвердити, чи видалення «залипло» через відкриті дескриптори
cr0x@server:~$ lsof +L1 | head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
nginx 1421 root 9w REG 0,113 1048576 0 5329156 /tank/data/logs/access.log
postgres 2198 postgres 11w REG 0,113 1073741824 0 5329901 /tank/db/pg_wal/000000010000002A000000B3
Значення: Файли видалені (NLINK=0), але процеси тримають їх відкритими. Простір не звільниться, доки ці дескриптори не закриються.
Рішення: Перезапустіть або посигналте служби, щоб вони відкрили логи заново (або зробіть ротацію правильно). Це може звільнити місце без торкання снепшотів.
Завдання 9: Виявити, хто зараз пише (і обережно його зупинити)
cr0x@server:~$ zpool iostat -v tank 2 3
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 26.6T 640G 420 3800 82M 610M
raidz2-0 26.6T 640G 420 3800 82M 610M
sda - - 70 640 14M 98M
sdb - - 66 640 13M 99M
sdc - - 73 940 14M 155M
sdd - - 71 580 14M 93M
---------- ----- ----- ----- ----- ----- -----
Значення: Інтенсивні записи йдуть, нерівномірно навантажуючи sdc. Хтось продовжує лити дані в майже повний пул.
Рішення: Паузуйте інгест, вимикайте debug-логи, зупиняйте пакетні завдання або переводьте систему в режим лише для читання для ураженого сервісу, доки не відновиться запас.
Завдання 10: Перевірити, чи справжній «повний» — це спеціальний vdev
cr0x@server:~$ zpool list -v tank
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 27.2T 26.6T 640G - - 72% 97% 1.00x ONLINE -
raidz2-0 27.0T 26.1T 900G - - 70% 97% - ONLINE
special 200G 198G 2.0G - - 15% 99% - ONLINE
Значення: Спеціальний vdev заповнений на 99%. Якщо метадані та малі блоки потрапляють туди, ви отримаєте помилки алокації, навіть якщо десь інше є вільне місце.
Рішення: Трактуйте це як термінову проблему. Ймовірно, треба додати ємність до спеціального vdev (додати дзеркальний пристрій і приєднати або перебудувати більший спеціальний vdev) та/або відкоригувати стратегію special_small_blocks. Швидких виправлень мало.
Завдання 11: Звільнити місце шляхом видалення снепшотів (безпечно і в правильному порядку)
cr0x@server:~$ zfs destroy tank/data@autosnap_2025-12-23_0000
cr0x@server:~$ zfs destroy tank/data@autosnap_2025-12-24_0000
cr0x@server:~$ zfs destroy tank/data@autosnap_2025-12-25_0000
Значення: Знищення снепшоту асинхронне за ефектом; ви можете не побачити миттєвого звільнення простору, якщо система зайнята, але тренд має піти в потрібному напрямку.
Рішення: Видаляйте найстаріші перші, коли політика дозволяє. Зупиніться, коли відновите безпечний запас (далі про те, скільки саме), потім виправте політику снепшотів, щоб не робити це знову о 3:00 ранку.
Завдання 12: Підтвердити відновлення простору на рівні пулу
cr0x@server:~$ zpool list tank
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 27.2T 25.9T 1.30T - - 69% 95% 1.00x ONLINE -
Значення: Ви отримали ~660 ГБ. Все ще мало, але ви відійшли від краю.
Рішення: Продовжуйте, поки не отримаєте оперативний запас (зазвичай 15–20% на завантажених пулах). Якщо видалення не дає результату — потрібне розширення ємності або міграція даних.
Завдання 13: Перевірити, чи датасет все ще обмежений квотою після відновлення пулу
cr0x@server:~$ zfs list tank/data
NAME USED AVAIL REFER MOUNTPOINT
tank/data 19.9T 100G 19.9T /tank/data
Значення: Пул тепер має більше вільного місця, але датасет має лише 100 ГБ вільного — узгоджується з refquota.
Рішення: Підвищте refquota, якщо доцільно, або переразподіліть дані в інший датасет з більшим запасом.
Завдання 14: Тимчасово підняти refquota (контрольовано, з логуванням, відкочувано)
cr0x@server:~$ sudo zfs set refquota=22T tank/data
cr0x@server:~$ zfs get -o name,property,value,source refquota tank/data
NAME PROPERTY VALUE SOURCE
tank/data refquota 22T local
Значення: Датасет тепер може посилатися до 22 ТБ, за умови, що пул має місце.
Рішення: Використовуйте це як тимчасовий захід. Потім впровадьте планування ємності та захисні механізми, щоб це не стало «просто піднімай знову» культурою.
Завдання 15: Знайти топ-споживачів простору всередині датасету (коли потрібно видаляти реальні дані)
cr0x@server:~$ sudo du -xhd1 /tank/backups | sort -h | tail -n 10
120G /tank/backups/tmp
540G /tank/backups/staging
1.8T /tank/backups/daily
2.4T /tank/backups/weekly
Значення: /tank/backups/weekly домінує. Саме тут важить обрізання.
Рішення: Видаляйте з найменш критичного рівня ретеншну першочергово. Потім налаштуйте завдання бекапу, щоб воно не створювало необмеженого зростання (часто таке водиться «зберегти назавжди» випадково).
Завдання 16: Перевірити, що інструменти утримання снепшотів не відтворюють проблему негайно
cr0x@server:~$ systemctl status zfs-auto-snapshot.timer
● zfs-auto-snapshot.timer - ZFS auto-snapshot timer
Loaded: loaded (/lib/systemd/system/zfs-auto-snapshot.timer; enabled; preset: enabled)
Active: active (waiting) since Thu 2025-12-26 09:05:12 UTC; 4h 12min ago
Trigger: Thu 2025-12-26 14:00:00 UTC; 42min left
Значення: Автоматичні снепшоти заплановані і ввімкнені.
Рішення: Не вимикайте це наосліп. Налаштуйте ретеншн, виключіть датасети, яким не потрібні часті снепшоти, і переконайтесь, що обрізка працює. Якщо доведеться призупинити це під час відновлення — поставте нагадування знову ввімкнути.
Завдання 17: Підтвердити feature flags та версійну контексту пулу (потрібно при зверненні по допомогу)
cr0x@server:~$ zpool get all tank | egrep 'feature@|ashift|autoreplace|autoexpand'
tank ashift 12 local
tank autoexpand off default
tank autoreplace off default
tank feature@spacemap_histogram enabled local
tank feature@allocation_classes active local
Значення: У вас активні класи алокації (поширено для спеціальних vdev), ashift=12 і autoexpand вимкнений.
Рішення: Плануючи зміни ємності, знайте, чи autoexpand вимкнений і чи класи алокації можуть брати участь у «є місце, але його не можна використати» поведінці.
Три корпоративні міні-історії з передової
Міні-історія №1 (хибне припущення): «Видалення даних звільнить простір».
Середня SaaS-компанія мала аналітичний кластер на ZFS. On-call отримав пейдж за API-аутейдж. Симптом: помилки записів, база скаржиться на «no space left on device». Пул показував 99% використання. On-call зробив те, що більшість зробили б у стресі: видалив директорію зі старими експортами.
Використання пулу не змінилося. Ні на відсоток. On-call видалив ще. Все одно нічого. Тепер у них була зламана служба і відсутність даних, які клієнт може пізніше запросити. Канал інциденту наповнився впевненими здогадами — завжди поганий знак.
Хибне припущення було простим: файлові видалення миттєво звільняють простір. На ZFS зі щільними снепшотами ці блоки все ще були посиланнями. Вони мали політику снепшотів, що робила їх щогодинними та тримала довше, ніж життєвий цикл даних. Чудово для точок відновлення. Жахливо для екстреного прибирання.
Відновлення було нудне, але правильне: ідентифікувати найбільших споживачів снепшотів, підтвердити вимоги з власником даних, знищити найстаріші снепшоти першими, а вже потім видаляти більше файлових даних. Вони відновили запас і сервіс. Постмортем ввів правило: «Не видаляти, поки не враховано снепшоти». Додали дашборд, що показує використаний простір снепшотами по датасетах, щоб наступному on-call не потрібна була теологія ZFS для триажу.
Міні-історія №2 (оптимізація, що відкотилася): недооцінений special vdev
Велика внутрішня команда платформи додала спеціальний vdev, щоб прискорити навантаження, що інтенсивно працюють з метаданими: мільйони малих файлів, багато операцій з директоріями і шари контейнерів. Воно працювало чудово. Затримки впали. Усі святкували і забули.
Через шість місяців вони потрапили в інцидент «pool full», хоча пул мав сотні гігабайт вільного місця. Проте нові створення файлів інколи падали. Перейменування зависало. Деякі датасети працювали нормально; інші «танули». Класичний частковий аутейдж: найгірший вид.
Винуватець — спеціальний vdev. Його розмір оцінювали оптимістично, базуючись на оцінках метаданих і порозі «малі блоки», що виявилося занадто широким. Він підтягнувся до 99% і тоді алокація метаданих стала вузьким місцем. Основні vdev були в порядку, що робило симптоми містичними.
Виправлення не було хитрим CLI-хаком. Це була ємність: перебудувати special vdev з більшими пристроями і виправити політику так, щоб special_small_blocks відповідав реальності. Вони також винесли операційну істину: спеціальні vdev потужні, але не опціональна інфраструктура. Моніторьте їх як пул і плануйте їх зростання так само, як плануєте ріст бази даних — бо по суті це ріст бази даних.
Міні-історія №3 (нудна, але правильна практика): квоти + ретеншн + запас врятували ситуацію
Поблизу фінансів підприємство з великими вимогами до відповідності використовувало ZFS для файлів та бекапів. Вони не були «швидко рухатись» типом. Вони мали квоти на користувацькі датасети, refquotas на шумні додатки, резервації для БД і політику снепшотів з чіткими рівнями ретеншну. Більшість інженерів приватно скептично ставилися.
Потім сторонній інструмент вийшов із-під контролю і почав писати debug-логи з вражаючою інтенсивністю. Пул почав повзти вгору. Але радіус ураження був обмежений: датасет інструмента досяг свого refquota і почав падати власними записами, не з’ївши весь пул. Резервація бази даних тримала. Домашні директорії користувачів залишалися записуваними. Інцидент зводився до «той інструмент поламався», а не «все впало».
Вони прибрали це вдень. Обрізали проблемний датасет, виправили ротацію логів і налаштували алерти на доступний простір по датасету, а не тільки по пулу. Нікому не довелося домовлятися про видалення критичних даних о 2:00 ранку.
Ось момент, де нудна команда виграє. Вони не уникнули інцидентів; вони зробили інциденти локальними. Квоти та політики ретеншну — не захопливо, але це операційний панцир.
Жарт #2: Найкращий час налаштувати ретеншн снепшотів був шість місяців тому. Другий найкращий час — до того, як ваше видалення «нічого не зробило», і ви почали торгуватися з файловою системою.
Типові помилки: симптом → корінна причина → виправлення
1) «Ми видалили дані, але використання пулу не впало»
Симптом: rm завершився; df і zpool list майже не змінилися.
Корінна причина: Снепшоти все ще посилаються на блоки, або видалені файли тримаються відкритими процесами.
Виправлення: Перевірте використання снепшотів (zfs list -t snapshot) і відкриті видалені файли (lsof +L1). Знищіть непотрібні снепшоти; перезапустіть процеси, що тримають файли; потім перевірте зміни вільного простору пулу.
2) «Пул має вільне місце, але додаток каже ENOSPC»
Симптом: Пул показує сотні ГБ вільного; датасет або додаток все ще падає при записі.
Корінна причина: Ліміт refquota/quota датасету, або резервація десь фіксує простір, або slop space заважає алокації.
Виправлення: Перевірте квоти/резервації (zfs get quota,refquota,reservation,refreservation). Розгляньте коригування обмежень свідомо та підтримуйте достатній запас пулу, щоб уникнути конфліктів зі slop space.
3) «Операції з маленькими файлами падають першими»
Симптом: Створення малих файлів не вдається; великі читання ще працюють; деякі датасети поводяться гірше.
Корінна причина: Спеціальний vdev повний (тиск на алокацію метаданих) або сильна фрагментація.
Виправлення: Перевірте алокацію спеціального vdev (zpool list -v). Додайте ємність або перебудуйте спеціальний vdev більшим; перегляньте special_small_blocks. Знизьте рівень заповнення і фрагментацію, відновивши запас.
4) «Все повільно, навіть читання»
Симптом: Висока затримка по всьому стеку близько 95–100% заповнення; затримки, пов’язані з TXG; скарги користувачів на «систему зависла».
Корінна причина: Суперечка за алокацію і фрагментація; інтенсивні синхронні записи; вузькі місця на рівні пристроїв, посилені під тиском.
Виправлення: Зупиніть важких записувачів, звільніть простір і розгляньте тимчасове зменшення швидкості запису (тротлінг на рівні додатка). Після відновлення впровадьте політику запасу та моніторинг фрагментації.
5) «Ми знищили снепшоти, але вільний простір все ще не відновився»
Симптом: Список снепшотів зменшився, але вільний простір пулу не збільшився як очікувалося.
Корінна причина: Простір утримується іншими снепшотами/клонованими даними; або інтенсивні поточні записи одразу споживають звільнений простір; або резервації/квоти плутають очікування.
Виправлення: Перевірте наявність клонів (zfs get origin), визначте головних записувачів (zpool iostat) і повторно перевірте резервації. Призупиніть записувачів під час прибирання, щоб фактично відновити запас.
6) «Ми додали ємність, але продуктивність не покращилась»
Симптом: Пул більше не повний, але затримки залишаються поганими.
Корінна причина: Фрагментація залишилася; спеціальний vdev все ще обмежений; навантаження синхронне; або дисковий дисбаланс.
Виправлення: Відновіть значущий запас (не лише 1–2%). Перевірте фрагментацію і використання спеціального vdev. Розгляньте зміни на рівні навантаження (батчування логів, вирівнювання recordsize), замість очікування, що лише ємність поверне продуктивність.
Чеклісти / покроковий план
Фаза 0: Стабілізація (зупинити кровотечу)
- Заморозьте найбільшого записувача. Пауза інгест-пайплайнів, вимкніть шалені debug-логи, зупиніть пакетні роботи або тимчасово зменшіть записувачі.
- Підтвердьте, що ви вирішуєте правильне обмеження. Пул повний проти квоти датасету проти спеціального vdev повного проти відкритих-видалених файлів.
- Комунікуйте простий статус. «Ми обмежені простором; ми звільняємо X; ETA для відновлення записів Y.» Тримайте повідомлення фактичним.
Фаза 1: Отримати негайний запас (швидкі перемоги)
- Закрийте видалені, але відкриті файли. Використайте
lsof +L1, перезапустіть служби коректно. - Обріжте найгірші снепшоти першими. Видаляйте найстаріші, з найбільшим
USED, які не потрібні. - Видаліть тимчасові не снепшотовані дані. Тимчасові каталоги, staging, кеші, старі артефакти збірки — лише після перевірки, що снепшоти їх не прикріпляють.
- Ціль для реального запасу. На завантажених пулах 10% часто все ще дискомфортно. Спробуйте 15–20% де можливе.
Фаза 2: Відновити нормальну роботу (зробити записи безпечними)
- Повторно вмикайте записувачі поступово. Слідкуйте за
zpool iostatта показниками помилок додатка; не переходьте від нуля до повного навантаження миттєво. - Перевірте квоти та резервації ще раз. Відкочуйте аварійні зміни обережно; підтвердіть адекватність лімітів датасетів.
- Запустіть scrub, якщо підозрювали апаратні проблеми. Якщо ви бачили помилки пристроїв, заплануйте scrub і заміну за потреби.
Фаза 3: Виправити систему (щоб не повторилось)
- Впровадьте зрозумілу політику ретеншну снепшотів. Щогодини на добу, щодня на тиждень, щотижня на місяць — що відповідає бізнесу. Зробіть це автоматизовано та під аудит.
- Алертуйте по датасету і по пулу. Пул на 80/85/90% з ескалацією; датасет avail нижче порогів для конкретних навантажень.
- Плануйте ємність на основі темпу росту, а не відчуттів. Відстежуйте тижневе зростання
zfs listused, дельти снепшотів і бекап-чарн. - Якщо використовуєте special vdev, розмірюйте його як продакшн-залежний. Бо так воно і є.
Запобігання: зробіть «пул повний» нудною подією
Політика запасу: виберіть число і дотримуйтесь його
Якщо ваш пул хостить щось чутливе до затримок або інтенсивно пишуче, ставте 80–85% як «жовтий», 90% як «червоний», 95% як «зупинити все». Ці пороги — не моральні судження, а операційні обмеження. Фрагментація і тиск алокатора не переймаються вашим роадмапом.
Дизайн датасетів: локалізуйте відмову
Розміщуйте «шумні» навантаження в окремих датасетах з refquota. Критичні системи (бази даних, образи VM) ставте в датасети з резервацією тільки якщо вам справді потрібен гарантований простір. Так ви не дасте логу вбити базу даних.
Дисципліна снепшотів: ретеншн — це продуктова функція
Снепшоти не безкоштовні. Це система ретеншну з профілем вартості, що спалахує при високому рівні змін. Визначте:
- Що ви снепшотите (не все заслуговує на однакову політику)
- Як часто (годинні/щоденні/щотижневі рівні)
- Як довго зберігаєте (і хто погоджує збільшення)
- Як обрізаєте (автоматично, з перевіркою, під моніторингом)
Спеціальні vdev: моніторьте їх як окремий пул
Якщо ви використовуєте special vdev, додайте алерти на їхню ємність і слідкуйте за впливом special_small_blocks. Багато команд ставляться до special vdev як до «кешу». Це не кеш. Це клас алокації, що може стати вашим першим жорстким лімітом.
Операційна гігієна, що окупається
- Ротація логів, яка протестована (не лише налаштована). Враховуйте випадок «процес тримає старий fd».
- Бекапи, що не вибухають снепшоти. Деякі робочі процеси бекапу створюють величезний churn; налаштуйте їх.
- Дашборди, що показують: ємність пулу, фрагментацію, використання снепшотів по датасетах і доступність датасетів (
avail). - Runbook-и, що містять правила ретеншну/відповідності вашої організації, щоб on-call не мусив домовлятися про політику під час інциденту.
Питання й відповіді
1) Що насправді відбувається, коли ZFS повністю заповнена?
Записи починають падати з ENOSPC, але не всі записи падають однаково. Помилки та зависання можуть виникати для алокацій метаданих, оновлень copy-on-write і синхронних записів раніше, ніж ви очікуєте. Продуктивність зазвичай деградує ще до жорсткої помилки.
2) Чому ZFS гальмує поблизу повного стану ще до помилок?
Вільний простір фрагментується. Алокатор працює важче, щоб знайти підходящі блоки, і I/O стає більш розпорошеним. На обертових дисках це особливо болісно; на SSD це також підвищує write amplification і затримки.
3) Чому видалення файлів не звільнило простір?
Найчастіше: снепшоти все ще посилаються на ці блоки, або файли видалені, але ще відкриті процесом. Використовуйте zfs list -t snapshot і lsof +L1, щоб підтвердити.
4) Чи варто знищувати снепшоти під час аутейджу?
Якщо снепшоти є причиною, що ви не можете звільнити простір, і політика ретеншну дозволяє — так. Знищення снепшотів зазвичай найчистіший спосіб звільнення. Але робіть це свідомо: оберіть снепшоти з найбільшим USED, підтвердьте бізнес-вимоги і видаляйте найстаріші першими.
5) Чи безпечно підвищувати quota/refquota щоб виправити ENOSPC?
З технічної точки зору це безпечно, але операційно ризиковано. Ви перекладаєте право споживання спільного простору. Використовуйте це тимчасово і поєднуйте з фіксом на ємність/ретеншн.
6) Скільки вільного місця слід тримати на пулі ZFS?
Для загальних змішаних навантажень: прагніть 15–20% запасу. Для переважно додавальних навантажень з низьким churn можна працювати щільніше, але ви купуєте ризик і затримку. Якщо не можете тримати запас — потрібно більше дисків або менше даних.
7) Чи можу я «дефрагментувати» пул ZFS після сильного заповнення?
Не прямо, як у старих файлових системах. Практичний метод — відновити запас і дозволити новим записам лягати краще, або мігрувати дані (send/receive) на свіжий пул для реального обнулення. Плануйте ємність, щоб не мусити героїчно рятувати ситуацію.
8) Що робити, якщо спеціальний vdev повний, але пул ні?
У вас точка тиску на алокацію метаданих. Потрібно збільшити ємність спеціального vdev (часто шляхом перебудови/розширення) і переглянути, які блоки туди потрапляють. Це не ситуація «видалити кілька файлів».
9) Резервації допомагають чи шкодять у ситуаціях «pool full»?
І те, і інше. Резервації захищають критичні датасети від шумних сусідів, що може врятувати день. Але вони також зменшують гнучкість в аварії. Використовуйте їх помірно і з чіткою відповідальністю та моніторингом.
10) Що спочатку: додати ємність чи видаляти?
Якщо ви можете безпечно і швидко видалити та відновити значущий запас — видаляйте спочатку. Якщо снепшоти/комплаєнс забороняють видалення або звільнення повільне порівняно з витратами аутейджу — додавайте ємність. Часто роблять обидва: додають ємність, щоб пережити, а потім видаляють для відновлення здорового запасу.
Наступні кроки
Пул ZFS, що заповнюється, рідко є несподіванкою; зазвичай він несподіваний лише для on-call, який не отримав потрібного сигналу вчасно. Коли це відбувається, виграшний хід — припинити спекуляції. Підтвердьте обмеження (пул проти датасету проти снепшотів проти спеціального vdev), звільніть простір найменш незворотною дією спочатку і відновіть запас до рівня, на якому ZFS може нормально алокувати.
Практичні кроки, які ви можете зробити цього тижня:
- Додайте алерти на ємність пулу, доступність датасетів (
avail) і використаний простір снепшотів по датасетах. - Напишіть і впровадьте політику ретеншну, що відповідає реальності бізнесу (а не оптимізму).
- Помістіть шумні навантаження під refquotas, щоб вони могли падати самі по собі.
- Якщо ви використовуєте special vdev, моніторьте та плануйте його ємність як першокласне сховище, а не аксесуар.
- Проведіть game day: симулюйте пул на 95%, пройдіть runbook і побачте, де процес ламається до того, як це станеться в продакшні.
Бо єдине гірше за повний пул — це повний пул під час вікна міграції, яке ви пообіцяли як «низький ризик».