02:17. Розгортання в процесі. Запис не вдається з помилкою ENOSPC. Хтось запускає df -h і оголошує, що файлову систему заповнено всього на 72%. Вітаю: ви зіткнулися з одним із улюблених трюків ZFS — коли система технічно права й одночасно операційно дратівлива.
Це не «баг» ZFS. Це ZFS, яка чесно повідомляє про інші обмеження, ніж ті, які ваша м’язова пам’ять перевіряє першою. Простір у ZFS — це не одне число. Це купа правил обліку, реалій метаданих і запасів безпеки, які проявляються лише тоді, коли ви вже в екстреному режимі.
Що насправді означає «немає місця» в ZFS
Коли додаток отримує ENOSPC на ZFS, це не завжди про сирі вільні байти. ZFS — це файлове середовище з копіюванням під час запису (copy-on-write). Кожне «перезаписування» — це новий запис десь інакше, оновлення метаданих, а старі блоки стають вільними лише після коміту групи транзакцій (TXG) — і тільки якщо ніхто інший не посилається на ці блоки.
Отже, «немає місця» може означати будь-що з цього:
- Пул насправді майже заповнений і ZFS захищає себе від краху (резервний простір, обмеження алокатора).
- Снапшоти прикріплюють блоки, які ви думали, що видалили.
- Резервації споживають простір, який
dfпогано описує. - Квоти блокують датасет, хоча в пулі є вільне місце.
- Метадані або накладні витрати на дрібні блоки пожирають залишковий доступний простір.
- Фрагментація і заповненість metaslab роблять «вільний простір» непридатним для конкретного патерну запису.
- Zvol з тонким провізуванням виглядає просторим, поки ним не стане; або здається повним через обмеження volsize/volblocksize.
Операційно слід сприймати «ZFS немає місця» як: «алокатор не може задовольнити запит з урахуванням поточних політик і посилань». Це відрізняється від «диск заповнений», і ця різниця має значення, бо виправлення рідко зводиться до «rm -rf, поки не запрацює».
Цитата, яку варто пам’ятати, коли хочеться «просто щось видалити» у продакшні: «Надія — не стратегія.»
— Rick Page
Швидкий план діагностики (перевірте це перед будь-яким видаленням)
Якщо нічого іншого не робите — виконайте це в порядку. План оптимізований за швидкістю, інформативністю та тим, щоб не погіршити інцидент.
1) Це на рівні пулу, конкретного датасету чи zvol?
- Пул:
zpool listіzpool status - Датасет:
zfs list,zfs get quota,reservation,refreservation - Zvol:
zfs list -t volume,zfs get volsize,volblocksize,refreservation
Рішення: якщо це квота/резервація датасету — виправлення локальні та швидкі. Якщо рівень пулу майже повний — потрібне управління простором, а не біганина зі налаштуваннями.
2) Снапшоти «прикріплюють» простір?
zfs list -t snapshot -o name,used,refer,creation -s usedzfs get usedbydataset,usedbysnapshots,usedbyrefreservation
Рішення: якщо снапшоти домінують, видалення файлів не допоможе; потрібно координаційно видаляти снапшоти.
3) Резервації або refreservation відбирають доступний простір?
zfs get -r reservation,refreservation- Перевірте несподівано великі
refreservationна zvol і датасетах.
Рішення: зменшуйте або прибирайте резервації лише якщо розумієте, навіщо вони були встановлені. «Бо хтось колись читав блог з оптимізацій» — не валідна причина.
4) Пул досягнув slop space / проблем алокатора?
zpool listдля перевірки великого відсотка заповнення.zpool get autotrimтаzpool statusдля помилок пристроїв і деградованих конфігурацій.
Рішення: якщо пул > ~80–90% та під навантаженням записів — плануйте негайне полегшення (звільніть реальний простір, додайте vdev-и, перемістіть навантаження). Не намагайтеся «дефрагментувати ZFS» — це не те, як це працює.
5) Перевірте «прихованих» споживачів: refreservation, special devices, дрібні блоки та синхронні записи
zfs get -r special_small_blocksі підтвердіть, що ви не сиплете метадані на занадто малий special vdev.zfs get recordsize,compressionдля датасетів з патологічно дрібними записами.
Рішення: якщо метадані/special заповнені — ви можете бачити «немає місця», навіть коли основний пул виглядає добре. Це потребує цілеспрямованого виправлення.
Цікаві факти та історичний контекст
- ZFS з’явився в Sun Microsystems у середині 2000-х, створений, щоб покласти край поділу «файлова система + менеджер томів», зробивши зберігання єдиним узгодженим стеком.
- Copy-on-write був вибором на користь надійності: ZFS уникає перезаписів на місці, щоб завжди зберігати консистентність на диску, навіть після збоїв.
- Концепція «пулу» перевернула стару модель: замість того, щоб файлові системи володіли розділами, вони стали дешево вираховуваними уявленнями над спільним пулом, що ускладнило облік.
- Снапшоти — це не копії; це закладки. Вони майже нічого не коштують при створенні, але можуть утримувати величезні об’єми «видалених» даних невизначено довго.
- Резервний простір (slop space) існує, бо майже повні пули поводяться погано: фрагментація зростає, алокація ускладнюється, і в гіршому випадку ви можете самі себе заблокувати від звільнення місця.
- Метадані у ZFS — першокласні та численні: контрольні суми, вказівники блоків, spacemap-и та журнали намірів означають, що система багато знає — і багато зберігає.
- Ashift став відомим через 4K диски: неправильне вирівнювання секторів назавжди зменшує корисну ємність і може підсилити біль від «немає місця» через втрати на вирівнювання.
- OpenZFS розвивався на різних платформах (Illumos, FreeBSD, Linux), і деякі поведінки щодо звітності простору та функцій відрізняються між версіями.
- Zvol зробили ZFS популярним для віртуалізації, проте вони принесли семантику блочного пристрою (volsize, volblocksize, discard/TRIM) у світ файлової системи з COW і снапшотами.
Облік простору, через який ZFS здається «брешучою»
df — не ваш авторитет тут
df питає змонтовану файлову систему, що вона вважає доступною для цього монтованого шару. У ZFS монт — це датасет з властивостями: квотами, резерваціями, refreservation і видом на пул, який може мати власні обмеження. Коли ZFS каже «немає місця», це може означати:
- Відсутність простору з точки зору алокатора пулу.
- Блокування через квоту датасету, навіть якщо в пулі є місце.
- Нездатність виділити потрібний впорядкований регіон у сильно заповненому metaslab (особливо для певних розмірів блоків і патернів).
Якщо ви налагоджуєте простір у ZFS, zfs і zpool — джерело істини. df — це як метеорологічний звіт на вікні.
Снапшоти: причина №1, чому видалення не «звільняє» простір
У ZFS блок звільняється лише коли ніхто на нього не посилається. Снапшот — це посилання. Тож якщо ви видалите файл, який існував на момент створення снапшоту, блоки все одно посилатимуться зі снапшоту. Результат: видалення «вдалося», додаток задоволений, а пул усе ще повний.
Математика простору ускладнюється, бо ZFS звітує snapshot USED як простір, який цей снапшот унікально утримує відносно поточного стану датасету. Це число може вводити в оману. Снапшоти можуть колективно утримувати велику кількість простору, навіть якщо кожен здається маленьким, залежно від ступеня змін.
Резервації і refreservations: простір, який ви не можете використовувати, хоч він і «вільний»
reservation гарантує простір для датасету. Це означає, що ZFS вважає цей простір недоступним для інших.
refreservation гарантує простір для посиланої даних датасету (без снапшотів). Його часто використовують для zvol-ів, щоб забезпечити можливість запису — бо вичерпання простору під блочним пристроєм може бути катастрофічним для файлової системи гостя.
Обидва — корисні інструменти. Але якщо виставлені необдумано, вони можуть виснажити ваш пул — ніби ви налаштовуєте SAN на цілу організацію 2009 року.
Slop space: політика «тримай трохи готівки в гаманці» у ZFS
ZFS резервує частину простору пулу, щоб система могла працювати, коли пул майже повний: виділяти метадані, комітити TXG і відновлюватися. Це іноді називають «slop space». Конкретна поведінка залежить від версії й налаштувань, але принцип стабільний: ZFS почне відмовляти в алокаціях до того, як ви досягнете 100% сирого використання.
Це не драматизація з боку ZFS. Файлова система з COW на 99% заповненості — це кошмар для продуктивності й надійності. Якщо ви регулярно тримаєте пули вище ~80–85% і дивуєтеся, коли починаються проблеми — це не проблема ZFS, це питання дорослих рішень.
Метадані і дрібні блоки: можна заповнити пул без «великих файлів»
ZFS зберігає контрольні суми, вказівники блоків, непрямі блоки, spacemap-и, структури директорій, розширені атрибути й інше. Якщо ви створюєте мільйони дрібних файлів або зберігаєте сильно фрагментовані дрібні блоки, накладні витрати на метадані зростають. Також дрібні блоки мають відносно більше вказівників і можуть витрачати простір через мінімальні розміри алокації.
Якщо ви використовуєте special vdev (для метаданих і/або дрібних блоків), ви можете отримати «немає місця», коли special vdev заповниться — навіть якщо основні vdev-и мають достатньо місця. Це особливий вид несподіванки.
Фрагментація і metaslab-и: «вільний» простір, який неможливо виділити
ZFS алокує з metaslab-ів. Коли пул заповнюється й відбувається churn, вільний простір дробиться на шматки, що занадто малі для потрібних розмірів або занадто дорогі для ефективної алокації. Алокатор може відмовити у запиті, навіть якщо загальний вільний простір виглядає ненульовим.
Це особливо болісно проявляється при:
- Великих послідовних записах на пізніх етапах життя пулу.
- VM-образах з випадковими записами, снапшотами і клонуванням.
- Занадто малому recordsize при великому churn.
Zvol-и: блочні пристрої з наслідками ZFS
Zvol-и виглядають як диски. Люди ставляться до них як до дисків. Потім дізнаються, що zvol-и підкріплені датасетами ZFS, а це означає, що снапшоти, refreservations, стиснення та поведінка COW можуть впливати на «немає місця».
Тонке провізування ускладнює ситуацію ще більше. Ви можете мати zvol з великим volsize, у вигляді багато вільного простору для гостя, і водночас заклинити хост-пул, поки записи не почнуть відмовляти. Гість бачить диск, що «повинен працювати». Хост бачить пул, який не може алоціювати. Обидва праві. Усі злі.
Жарт №1: Найшвидший спосіб збільшити вільне місце в пулі ZFS — це зробити снапшот своєї кар’єри перед тим, як торкатися продакшену. Вам захочеться мати до чого відкотитися.
Практичні завдання (команди, виводи, рішення)
Це ті завдання, які я реально виконую, коли ZFS повідомляє ENOSPC або пул поводиться «повним» і це не відповідає df. Кожне завдання містить реалістичний приклад виводу і яке рішення з нього випливає.
Завдання 1: Підтвердити заповненість пулу і базове здоров’я
cr0x@server:~$ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 21.8T 19.9T 1.93T - - 62% 91% 1.00x ONLINE -
Що це означає: 91% заповнення і 62% фрагментація — тривожний сигнал. Навіть при 1.93T вільних алокація може зазнати невдач під навантаженням, а продуктивність буде поганою.
Рішення: розглядайте це як інцидент на рівні пулу. Основне виправлення — звільнити значний простір або додати потужність vdev-ів, а не «видалити пару логів».
Завдання 2: Перевірити, чи квота датасету спричиняє локальний ENOSPC
cr0x@server:~$ zfs get -o name,property,value,source quota,refquota tank/app
NAME PROPERTY VALUE SOURCE
tank/app quota 2T local
tank/app refquota none default
Що це означає: датасет tank/app обмежений квотою 2T незалежно від вільного місця в пулі.
Рішення: якщо додатку потрібно більше — підніміть квоту; якщо ні — додаток має очищатися в межах бюджету.
Завдання 3: Перевірити резервації і refreservation рекурсивно
cr0x@server:~$ zfs get -r -o name,property,value,source reservation,refreservation tank | head
NAME PROPERTY VALUE SOURCE
tank reservation none default
tank refreservation none default
tank/vm reservation none default
tank/vm refreservation none default
tank/vm/win01 reservation none default
tank/vm/win01 refreservation 500G local
tank/vm/win02 reservation none default
tank/vm/win02 refreservation 500G local
Що це означає: дві віртуальні машини мають по 500G refreservation. Це 1T пулового простору, ефективно виключеного для інших.
Рішення: тримайте refreservation лише там, де потрібні тверді гарантії. Якщо пул у стресі — зменшуйте їх обережно і документуйте причину.
Завдання 4: Побачити, що споживає простір за категоріями
cr0x@server:~$ zfs get -o name,property,value -s local,default used,available,usedbysnapshots,usedbydataset,usedbyrefreservation tank/app
NAME PROPERTY VALUE
tank/app used 1.89T
tank/app available 110G
tank/app usedbydataset 940G
tank/app usedbysnapshots 850G
tank/app usedbyrefreservation 0B
Що це означає: снапшоти утримують майже стільки ж, скільки й живий датасет.
Рішення: видалення файлів у tank/app не допоможе. Спочатку працюйте зі снапшотами: політика зберігання, реплікація або цільове видалення снапшотів.
Завдання 5: Ідентифікувати найбільші снапшоти (за значенням used)
cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -s used | tail -5
tank/app@auto-2025-12-20_0100 120G 820G Sat Dec 20 01:00 2025
tank/app@auto-2025-12-21_0100 128G 812G Sun Dec 21 01:00 2025
tank/app@auto-2025-12-22_0100 140G 800G Mon Dec 22 01:00 2025
tank/app@auto-2025-12-23_0100 155G 785G Tue Dec 23 01:00 2025
tank/app@auto-2025-12-24_0100 210G 740G Wed Dec 24 01:00 2025
Що це означає: останні снапшоти стрімко зростають; churn високий.
Рішення: перегляньте, що змінилося (нове навантаження, робота з compact, помилка ротації логів) і відкоригуйте частоту/утримання снапшотів або структуру датасету.
Завдання 6: Провести dry-run плану видалення снапшотів (перевірка людиною перш ніж виконувати)
cr0x@server:~$ zfs list -t snapshot -o name -s creation | head -5
tank/app@auto-2025-11-01_0100
tank/app@auto-2025-11-02_0100
tank/app@auto-2025-11-03_0100
tank/app@auto-2025-11-04_0100
tank/app@auto-2025-11-05_0100
Що це означає: у вас є впорядкований список для пропозицій видалення (наприклад, найстаріші перші) у відповідності з політикою.
Рішення: якщо треба видаляти снапшоти, робіть це від найстаріших, хіба що у вас є відомий «поганий снапшот», який фіксує конкретний стан, який більше не потрібен.
Завдання 7: Фактично видаляти снапшоти (обережно, бажано пакетно)
cr0x@server:~$ sudo zfs destroy tank/app@auto-2025-11-01_0100
cr0x@server:~$ sudo zfs destroy tank/app@auto-2025-11-02_0100
Що це означає: посилання снапшотів видаляються; простір буде звільнено, коли інші посилання відсутні і TXG закомітиться.
Рішення: після кількох видалень перевірте zpool list і available датасету. Якщо нічого не змінилося — грає роль інше обмеження (клони, холди, резервації, special vdev).
Завдання 8: Перевірити холди на снапшотах, які заважають видаленню
cr0x@server:~$ zfs holds tank/app@auto-2025-11-03_0100
NAME TAG TIMESTAMP
tank/app@auto-2025-11-03_0100 keep Thu Dec 12 09:14 2025
Що це означає: холд з ім’ям keep прив’язує снапшот.
Рішення: координуйтеся з тим, хто поставив холд (інструменти бекапу/реплікації). Прибирайте холд лише коли впевнені, що він більше не потрібен.
Завдання 9: Зняти холд (усвідомлено)
cr0x@server:~$ sudo zfs release keep tank/app@auto-2025-11-03_0100
cr0x@server:~$ sudo zfs destroy tank/app@auto-2025-11-03_0100
Що це означає: снапшот тепер можна знищити.
Рішення: якщо холди з’являються несподівано — проведіть аудит pipeline-ів бекапу/реплікації. Холди корисні; несподівані холди — погано.
Завдання 10: Перевірити, чи клон не тримає снапшот живим
cr0x@server:~$ zfs get -o name,property,value clones tank/app@auto-2025-12-01_0100
NAME PROPERTY VALUE
tank/app@auto-2025-12-01_0100 clones tank/app-test
Що це означає: датасет tank/app-test — клон, що залежить від цього снапшоту. Ви не можете знищити снапшот, не розв’язавши питання з клоном.
Рішення: або видалити клон, або promote його, або прийняти, що снапшот має залишитися. Не «форсуйте» через це, якщо не хочете пояснювати втрату даних.
Завдання 11: Визначити, чи zvol не надто зарезервований або неправильно розмірений
cr0x@server:~$ zfs list -t volume -o name,volsize,used,available tank/vm/win01
NAME VOLSIZE USED AVAIL
tank/vm/win01 800G 610G 0B
Що це означає: AVAIL — 0B для цього перегляду датасету тому. Це може бути через квоту/refreservation або обмеження пулу. Також може значити, що ваш zvol досяг свого ліміту з урахуванням умов пулу.
Рішення: перевірте refreservation і заповненість пулу. Якщо пул майже повний, збільшення volsize ризиковане або неможливе.
Завдання 12: Перевірити властивості zvol, що впливають на поведінку простору
cr0x@server:~$ zfs get -o name,property,value -s local,default volsize,volblocksize,compression,refreservation tank/vm/win01
NAME PROPERTY VALUE
tank/vm/win01 volsize 800G
tank/vm/win01 volblocksize 8K
tank/vm/win01 compression lz4
tank/vm/win01 refreservation 800G
Що це означає: refreservation 800G гарантує повний volsize. Добре для безпеки, жорстоко для спільних пулів.
Рішення: якщо потрібні гарантії — тримайте. Якщо ви управляєте щільним хостом віртуалізації і нестача простору — розгляньте зменшення refreservation і прийняття операційного ризику (з моніторингом і запасом).
Завдання 13: Перевірити, чи пул має контрольну точку (checkpoint), що займає «фантомний» простір
cr0x@server:~$ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 21.8T 19.9T 1.93T 1.2T - 62% 91% 1.00x ONLINE -
Що це означає: існує checkpoint, який утримує 1.2T старого стану пулу. Це реальний простір, який ви не зможете повернути, поки не скинете контрольну точку.
Рішення: якщо вам не потрібен rollback — видаліть checkpoint. Якщо потрібен — ви вирішили працювати з меншим запасом ємності — прийміть це рішення.
Завдання 14: Видалити checkpoint (неповоротно, думайте перед виконанням)
cr0x@server:~$ sudo zpool checkpoint -d tank
cr0x@server:~$ zpool list tank
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 21.8T 19.9T 1.93T - - 62% 91% 1.00x ONLINE -
Що це означає: checkpoint видалено; цей прикований простір тепер можна звільнити у міру звільнення блоків.
Рішення: робіть це лише коли впевнені, що не потрібен rollback-переріз.
Завдання 15: Перевірити стан і заповненість special vdev (якщо він є)
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
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
special
mirror-1 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
errors: No known data errors
Що це означає: існує special vdev. Якщо він заповнюється, пул може ефективно «вичерпати» простір для метаданих/дрібних блоків.
Рішення: уважно моніторьте використання special vdev. Якщо він близький до повного, можливо, потрібно додати спеціальну ємність або відкоригувати стратегію special_small_blocks.
Завдання 16: Перевірити політику дрібних блоків, що може перевантажити special vdev
cr0x@server:~$ zfs get -r -o name,property,value special_small_blocks tank | head
NAME PROPERTY VALUE
tank special_small_blocks 16K
tank/app special_small_blocks 16K
tank/vm special_small_blocks 0
Що це означає: будь-які блоки ≤16K для tank і tank/app потрапляють на special. Це може чудово підвищити продуктивність і катастрофічно спустошити special, якщо робоче навантаження має багато дрібних блоків.
Рішення: якщо special зайнятий — зменшіть це для churn-ових датасетів (нові записи підпадатимуть під нове правило; старі блоки не мігрують самі по собі).
Жарт №2: ZFS не «з’їдає» ваш вільний простір. Вона просто веде скрупульозні чеки, і ваші видалення не стають податковими відрахуваннями, поки снапшоти цього не підтвердять.
Три корпоративні міні-історії з війни за простір
Міні-історія 1: Інцидент через хибне припущення
Компанія мігрувала застарілий сервіс у контейнери. Зберігання було «простим»: ZFS-датасет змонтований у ноди з погодинними снапшотами для безпеки. План реагування був успадкований з епохи ext4: якщо диск повний — видаліть старі логи і перезапустіть.
У піковий день записи почали відмовляти. Додаток викидав ENOSPC і впадав у цикл перезапусків. On-call перевірив df -h: 68% використано. Вони підозрювали баг. Перезапускали поди. Агресивніше крутили логи. Нічого не допомогло.
Потім хтось запустив zfs get usedbysnapshots і виявив, що снапшоти утримують більше простору, ніж живий датасет. Команда недавно ввімкнула детальне логування запитів для дебагу і розгорнула зміну, яка багато разів перезаписувала великий JSON-файл. Щогодини новий снапшот прикріплював черговий шматок цього churn. Видалення поточних логів не зачепило прикріплені блоки.
Виправлення було нудне: видалили купу старіших снапшотів і зменшили частоту знімків для цього датасету. Постмортем дав чіткий урок: «df не є авторитетом щодо ZFS» став рядком у runbook, а команда додала дашборд для usedbysnapshots і заповнення пулу.
Міні-історія 2: Оптимізація, що обернулася проти
Команда платформи віртуалізації хотіла пришвидшити VМ. Вони додали special vdev на дзеркальних NVMe для прискорення метаданих і дрібних блоків. Також встановили special_small_blocks=32K на весь пул, бо в лабораторії виглядало добре. Усі святкували; графіки покращилися.
Місяцями потому нова внутрішня система збірки оселилася на цьому ж пулі. Вона створювала океани дрібних файлів, постійно їх чурнила й любила перезаписувати невеликі бінарні об’єкти. Special vdev почав заповнюватись значно швидше за основні vdev-и. Ніхто не помітив, бо пул все ще мав «терабайти вільних», і єдине сповіщення було загальним «заповнення пулу».
Потім почалися випадкові помилки «немає місця» в не пов’язаних сервісах. Виділення метаданих відмовлялося, бо special був тісний. Деякі датасети взагалі не використовували дрібні блоки, але їм теж потрібні були метадані. Команду зберігання звинуватили в «брехні ZFS».
Зрештою довелося додати більше special-ємності і звузити special_small_blocks лише до датасетів, яким це справді допомагає. Урок болісний: «швидкі» налаштування мають радіус ураження. Не розгортайте їх на весь пул тільки тому, що бенчмарк виглядає красиво.
Міні-історія 3: Нудна, але правильна практика, що врятувала день
Система, близька до фінансів, зберігала щоденні звіти і одночасно піддавала їх клієнтам. Команда застосовувала суворі квоти на датасети і політику, що пул ніколи не перевищує операційного порогу. Вони трактували 80–85% як «повний» для пулу, бо вже бачили наслідки перевищення цього порогу.
Одної п’ятниці постачальник змінив формат фіду і парсер почав дублювати дані. Споживання простору різко зросло. Сервіс був ще здоровий, але пул швидко підбирався до порогу. Алерти спрацювали заздалегідь, бо були налаштовані на заповнення пулу і ріст снапшотів — не тільки на видимі клієнту відмови.
Відповідь команди була непомітною: вони призупинили інгест, тримали сторону обслуговування працюючою і використали снапшоти для збереження доказів для дебагу. Оскільки пул мав запас, це можна було зробити без паніки алокатора або екстрених видалень. Вони виправили парсер, відновили коректні дані і продовжили роботу.
Постмортем був короткий і трохи самовдоволений. «Нудна практика» — це просто тримати запас, застосовувати квоти і моніторити usedbysnapshots. Нікому не довелося випадково щось видаляти. Нікому не довелося пояснювати, чому бекапи зникли. Іноді найкраща інженерія — це відмова працювати на межі.
Поширені помилки: симптом → причина → виправлення
1) «df показує багато місця, але записи відмовляють»
Симптом: додаток отримує ENOSPC; df -h показує комфортний вільний простір.
Корінь проблеми: квота датасету, reservation/refreservation або slop space / обмеження алокатора пулу.
Виправлення: перевірте zfs get quota,refquota,reservation,refreservation і zpool list. Відрегулюйте відповідну властивість або звільніть простір у пулі.
2) «Я багато видалив, але нічого не звільнилося»
Симптом: ви видаляєте файли; алокація пулу не знижується.
Корінь проблеми: снапшоти (або клони) утримують блоки.
Виправлення: визначте usedbysnapshots. Ідентифікуйте важкі снапшоти, холди і клони; видаляйте снапшоти згідно з політикою або видаліть/просуньте клони.
3) «Пул на 90% заповнений і раптом усе повільно і відмовляє»
Симптом: різкий ріст латентності, періодичні відмови алокацій, повільні scrub-и, випадкові IO проблеми.
Корінь проблеми: поведінка алокатора при майже повному пулі + фрагментація. COW потребує місця для «дихання».
Виправлення: звільніть суттєвий простір (не кілька гігабайт, а значущі відсоткові пункти), додайте vdev-и або мігруйте навантаження. Потім встановіть обмеження.
4) «Ми додали special vdev і тепер «немає місця» трапляється раніше»
Симптом: у пулу багато сирого вільного місця; навантаження, що тяжіє до метаданих, відмовляє; помилки виглядають як вичерпання простору.
Корінь проблеми: special vdev заповнений або майже заповнений через політику метаданих/дрібних блоків.
Виправлення: моніторте і розширюйте special vdev; обмежте special_small_blocks для конкретних датасетів; не надсилайте churn-ові дрібні блоки туди, якщо ви не розрахували ємність.
5) «Файлова система гостя zvol каже, що є місце, а хост каже ENOSPC»
Симптом: записи з VM відмовляють; у гостя є вільне місце; пул хоста майже повний або тонко провізований.
Корінь проблеми: тонке провізування + COW + снапшоти + відсутність запасу; або схема резервацій zvol, що обкрадає пул.
Виправлення: додайте запас, зменшіть churn снапшотів, забезпечте discard/TRIM наскрізно де доречно і вирішіть, чи потрібна refreservation.
6) «Ми ввімкнули dedup, щоб зекономити місце; тепер в нас немає місця»
Симптом: математика ємності погіршала; тиск на пам’ять збільшився; поведінка простору стала непередбачуваною.
Корінь проблеми: dedup додає метадані й операційні витрати; у багатьох навантаженнях це пастка, якщо не сплановано ретельно.
Виправлення: не вмикайте dedup легковажно. Якщо ви вже це зробили, виміряйте вплив і розгляньте міграцію даних у недедуп-пул/датасет замість спроб «вимкнути» як чарівний спосіб відкотити наслідки.
Контрольні списки / поетапний план
Контрольний список A: «Зупинити кровотечу» під час інциденту ENOSPC
- Підтвердити масштаб: пул чи датасет чи zvol. Запустіть
zpool listіzfs list. - Заморозити churn: призупиніть роботу, що генерує записи (інгест, compact, бекапи, CI-артефакти). Інциденти простору погіршуються при churn.
- Знайти обмеження: квоти/резервації/снапшоти/special vdev. Не вгадуйте.
- Безпечно відновити простір: видаляйте снапшоти згідно з політикою (найстаріші першими), зменшуйте резервації або переміщуйте датасет в інший пул.
- Підтвердити відновлення: повторно перевірте
CAPпулу,availableдатасету і успішність записів додатку. - Задокументувати зміни: видалення снапшотів, зміни властивостей — усе. Майбутнє «я» — зацікавлена сторона.
Контрольний список B: «Щоб це більше не повторилося»
- Встановіть операційний поріг для використання пулу (звично 80–85% залежно від навантаження) і сповіщення досягнення порогу.
- Моніторте ріст снапшотів по датасетах, а не лише загальне використання пулу.
- Використовуйте квоти усвідомлено для «галасливих сусідів» і runaway job-ів.
- Використовуйте резервації помірковано і тільки там, де гарантії коштують витрат із загального пулу.
- Для віртуалізації: визначте політику для тонкого провізування; якщо дозволяєте — контролюйте запас і моніторьте агресивно.
- Перегляньте стратегію special vdev як план ємності, а не як налаштування-підвищення продуктивності.
- Проводьте регулярні scrub-и і ставтесь до будь-яких помилок пристроїв як до термінових. Інциденти простору та надійності часто приходять разом.
Питання та відповіді (FAQ)
1) Чому ZFS каже «немає місця» до того, як пул досягне 100%?
Тому що ZFS тримає резервний простір (slop space) і потребує місця для метаданих та коміту TXG. Біля 100% COW-файлова система може себе «заплутати».
2) Чому видалення файлів не звільнило місце?
Мабуть, снапшоти (або клони) все ще посилаються на ці блоки. Перевірте zfs get usedbysnapshots і переліку снапшотів за used.
3) Чи безпечно видаляти снапшоти, щоб звільнити простір?
Зазвичай так — якщо ви розумієте, навіщо вони існують (бекап, реплікація, точки відкату). Небезпека — видалити не ті снапшоти без координації щодо політики зберігання.
4) У чому різниця між reservation і refreservation?
reservation резервує простір для датасету включно зі снапшотами. refreservation резервує простір лише для реферованих даних датасету, часто використовується для безпеки zvol.
5) Чи може сама фрагментація спричинити ENOSPC?
Вона може сприяти. Коли metaslab-и переповнені і фрагментовані, алокація для певних розмірів блоків може зазнавати невдачі, навіть якщо залишається якийсь загальний вільний простір, особливо під сильним churn.
6) Чи допоможе стиснення при «немає місця»?
Стиснення може зменшити алокований простір і відкласти проблему, але це не порятунок, якщо ви вже близькі до повного і старі блоки прикріплені снапшотами.
7) Чому snapshot USED виглядає малим, хоча снапшоти утримують багато простору?
USED снапшоту — це те, що унікально належить цьому снапшоту відносно поточного стану датасету. Багато снапшотів можуть кожен виглядати скромно, але разом фіксувати великий історичний churn.
8) Чи варто просто додати більший диск у пул?
Додавайте ємність правильно: пули ZFS ростуть шляхом додавання vdev-ів, а не просто заміни одного диска (хіба ви не замінюєте кожен диск у vdev і не розширюєте). Збільшення ємності — хороше рішення, коли воно сплановане, а не панічне.
9) Чи може заповнення special vdev спричинити загально-пулові помилки запису?
Так. Якщо метадані (або дрібні блоки, спрямовані в special) не можна алоціювати, звичайні записи можуть відмовляти. Спеціальна ємність — не опція, коли ви на неї покладаєтесь.
10) Скільки вільного місця потрібно тримати в пулі ZFS?
Достатньо, щоб ви не грали в рулетку алокатора. Для багатьох робочих навантажень розглядайте 80–85% як «повний». Для пулів з VM і випадковими записами будьте ще більш обережні.
Висновок: наступні кроки, які можна зробити сьогодні
Якщо ви зараз у інциденті: зупиніть churn, визначте, чи справжній пожирач простору — снапшоти чи резервації, і звільніть місце способом, який ви зможете пояснити в постмортемі. Випадкові видалення — це шлях від інциденту через нестачу простору до інциденту з втратою даних.
Якщо інциденту немає (рідка розкіш): встановіть поріг заповнення пулу, моніторьте usedbysnapshots і резервації, і відрепетируйте кроки «швидкої діагностики», щоб не вчитися цього о 2-й ночі. Мета — не змусити ZFS перестати «брехати». Мета — говорити мовою ZFS до того, як вона почне кричати.