Облік місця в ZFS: чому du і zfs list не збігаються

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

Якщо ви використовували ZFS у бойових умовах — на хості бази даних, у фермі віртуальних машин або на файловому сервері, який непомітно перетворився на озеро даних — ви бачили це: du клянеться, що датасет займає 2.1T, але zfs list наполягає, що він використовує 3.4T. Хтось запитує: «То звідки з’явився додатковий терабайт?» — і раптом ви займаєтеся реагуванням на інцидент із калькулятором.

Це не помилка ZFS. Це облік. ZFS повідомляє кілька «правд» залежно від запитання, яке ви ставите. du — це обхід файлової системи. zfs list — це облік володіння блоками з урахуванням снапшотів, резервацій, метаданих і політик на рівні пулу, як-от slop space. Коли ви узгоджуєте запитання, числа теж узгоджуються — здебільшого. Коли ні — виникають сюрпризи, які виглядають як витоки.

Головна невідповідність: файли vs блоки vs історія

du відповідає: «Скільки дискових блоків зараз виділено для файлів, до яких я можу дістатися, обходячи це дерево директорій прямо зараз?»

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

Теж саме сховище, інше питання. Цю різницю підсилюють визначальні особливості ZFS:

  • Copy-on-write означає, що старі блоки залишаються доти, поки на них посилаються снапшоти.
  • Стиснення означає, що «байти у файлах» і «байти на диску» — це різні валюти.
  • Індиректні блоки, метадані та накладні витрати spacemap існують навіть тоді, коли ваша директорія виглядає «порожньою».
  • Поведінка на рівні пулу (slop space) приховує частину ємності, щоб система залишалася живою.

Жарт №1: Питати «чому du і zfs list не збігаються» — це як питати «чому баланс у банку не сходиться з моїм трекером витрат» — один враховує очікувані транзакції, інший — ваш оптимізм.

Факти й історичний контекст, що справді важливі

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

  1. ZFS зробив популярними copy-on-write снапшоти в загальноцільових файлових системах; цей вибір робить використання місця по суті залежним від часу.
  2. Початкова лінія ZFS походить із Solaris, де операційною метою був не «ноутбук», а «сервер зберігання, який не повинен корумпувати дані, коли все йде неправильно».
  3. Звітування про простір в ZFS розвивалося: сучасні OpenZFS експонують властивості як usedbydataset, usedbysnapshots і logicalused, щоб зменшити невизначеність.
  4. Поведінка «1/8 slop space» існує, щоб зменшити катастрофічні режими відмов при заповненні пулу; це не UI-жарт.
  5. Історично адміністратори заповнювали файлові системи до 99%, бо інструменти ери ext вчили, що так можна; ZFS карає за таку звичку, бо розподіл і поведінка metaslab погіршуються при майже повному пулі.
  6. Стиснення перейшло від «нішева оптимізація» до «рекомендовано за замовчуванням» для багатьох розгортань ZFS, бо сучасні CPU дешеві, а диски — ні.
  7. Спеціальні vdev (метадані/дрібні блоки на швидкій пам’яті) змінили профіль продуктивності для навантажень з дрібними файлами, але також додали нові способи витратити не той тип простору.
  8. Снапшоти дешеві в сенсі «створення», але не в сенсі «зберігати назавжди»; рахунок приходить при великому обсязі змін.
  9. Зображення ВМ і шари контейнерів зробили «розріджений файл + зміна + снапшоти» поширеним рецептом провалу; такого масштабу не було, коли ZFS народився.

Практична ментальна модель простору ZFS

Коли ви читаєте статистику простору ZFS, тримайте в голові три «відра»:

1) Логічні байти (що думають додатки, що вони записали)

Це розміри файлів, сторінки баз даних, «віртуальна ємність» образів ВМ. Це те, про що люди хочуть думати. ZFS може показати це через logicalused та logicalreferenced.

2) Фізичні байти (що реально займає пул)

Це те, що визначає, чи ви досягнете 80%, 90% і потім «все горить». Стиснення, копії, накладні RAIDZ, метадані — все тут. ZFS показує це через used, referenced та детальніші поля usedby*.

3) Володіння/атрибуція (хто «володіє» блоками в часі)

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

Що вимірює du (і що ігнорує)

du обходить директорії й сумує виділені блоки для доступних файлів. Це корисно, але воно має сліпі плями в ZFS:

  • Снапшоти: Снапшот не є частиною живого дерева директорій, тому du ігнорує простір, закріплений снапшотами, якщо ви явно не обходите .zfs/snapshot (якщо він відображений).
  • Метадані та накладні витрати датасету: du рахує виділені блоки файлів, але не метадані ZFS, як-от вказівники блоків, накладні spacemap і індексні блоки, які зростають із фрагментацією та змінами.
  • Правдивість при стисненні: du зазвичай показує виділені блоки з огляду ОС. Для ZFS це може бути ближче до «фізичного», ніж «логічного», але точна поведінка залежить від платформи та прапорів (--apparent-size vs за замовчуванням).
  • Резервації: Якщо датасету виділено reservation, пул має зарезервовану ємність, але du цього не покаже.
  • Порожнини/розріджені області: du рахує виділені блоки; розріджені нулі не рахуються, якщо не були записані.

Що вимірює zfs list (і чому здається «більше»)

zfs list — це облік блоків, а не обхід директорій. Його колонки за замовчуванням вводять в оману своєю простотою:

  • USED: фізичний простір, спожитий датасетом і нащадками (залежно від контексту), включаючи простір, на який посилаються снапшоти.
  • AVAIL: що ZFS дозволить вам виділити, з урахуванням вільного простору пулу, квот, резервацій і slop space.
  • REFER: фізичний простір, доступний цьому датасету (не враховуючи нащадків).

Ці слова точні, але неповні. У продакшені майже завжди хочеться отримати розбивку колонок, бо USED — це складна сума.

Снапшоти: звичайний підозрюваний

Більшість розбіжностей між du і zfs list — це «снапшоти утримують видалені/перезаписані блоки». Copy-on-write означає, що модифікації виділяють нові блоки, а снапшоти зберігають старі. Якщо ви видалите сьогодні директорію розміром 500G, а вчорашній снапшот досі існує, ті блоки залишаються в пулі.

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

Жарт №2: Снапшоти — це як та «тимчасова» канал у Slack — дешево створювати, дорого зберігати, і ніхто не хоче видаляти його.

Стиснення, логічний простір і чому людей вводять в оману

Стиснення — це місце, де інтуїція гине. На датасеті зі стисненням:

  • ls -l показує логічний розмір файлу.
  • du (за замовчуванням) часто показує виділений простір, який може ближче відповідати фізичному використанню.
  • zfs list USED — це фізичне використання (з нюансами снапшотів/резервацій).
  • zfs get logicalused показує логічне використання (що було записано до стиснення).

Отже, ви можете побачити du менше, ніж zfs list, тому що снапшоти закріплюють старі блоки, але також можете побачити протилежне: du --apparent-size може показати «більше», ніж фізична реальність через стиснення.

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

Розріджені файли, zvol і «виділено» vs «записано»

Розріджені файли — класичний генератор невідповідностей: образ диска ВМ може мати логічний розмір «1T», але лише 80G виділено. du та фізичні статистики ZFS часто погоджуються щодо «виділеного», тоді як команди додатків продовжують цитувати логічний розмір і дивуються, чому «не вміщується».

Zvol додають ще один шар: це блочні пристрої всередині ZFS. Вони можуть бути товстими або тонкими залежно від налаштувань (volmode, поведінка провізування та шаблон записів гостя). Снапшотування zvol у стосі ВМ поширене; це також чудовий спосіб зберегти вражаючу кількість змін.

Накладні витрати метаданих, xattrs, ACL і податок на дрібні файли

Деякі робочі навантаження — це в основному метадані: мільйони дрібних файлів, багато xattrs, дерева з ACL або патерни типу maildir. Накладні витрати метаданих ZFS не безкоштовні, і вони не відображаються як «байти файлів». du може недооцінювати відбиток, бо він сумує виділені блоки файлів, а не всі індексні блоки, dnode і структури метаданих, потрібні для цілісності та швидкості файлової системи.

Якщо ви коли-небудь бачили, як датасет «дрібних файлів» з’їдає пул, ви перестаєте довіряти середнім як «файли лише по 4K». Файл може бути 4K; екосистема навколо файлу — це решта вашого вікенду.

Резервації, квоти, refreservation і slop space

Резервації створюють «фантомне використання» з точки зору du. ZFS може відкласти простір для датасету (reservation або refreservation), навіть якщо файли ним не користуються. ZFS повідомляє цей зарезервований простір як використаний/недоступний, бо він обіцяний комусь.

Квоти (quota, refquota) обмежують виділення. Вони безпосередньо не пояснюють невідповідності du vs zfs list, але пояснюють, чому AVAIL менше, ніж очікувалося.

Потім є slop space: ZFS зазвичай утримує частину вільного простору пулу, щоб оновлення алокацій та метаданих не відмовляли катастрофічно біля 100%. Тож навіть якщо у вас «є» вільне місце, ZFS може відмовитися його видати.

copies=2, спеціальні vdev і інші підводні камені

Властивість copies — це мовчазний множник: copies=2 зберігає дві копії даних користувача (в межах того самого пулу). Добре для певних потреб надійності; жахливо, якщо ви забудете, що її ввімкнули, і потім порівнюватимете з du.

Спеціальні vdev (метадані/дрібні блоки на SSD/NVMe) можуть зробити ZFS схожим на іншу файлову систему. Але вони також створюють другу домену ємності: ви можете вичерпати простір спеціального vdev, поки основний пул виглядає добре. Ваша «проблема простору» перетворюється на «заповнений неправильний vdev», і симптоми тонкі, поки не стануть одразу помітні.

Три історії з корпоративного світу

Міні-історія 1: Інцидент через неправильне припущення

Тикет почався як скарга фінансів: «Сховище стягує з нас плату на 40% більше, ніж ми зберігаємо». Команда витягнула du з директорії проєкту і була впевнена. Числа були маленькі. Числа для нарахування були великими. Хтось зробив висновок, що звіти команди зберігання надуті, і ескалував.

Ми подивилися на датасет і побачили звичний патерн: CI-система генерувала артефакти, видаляла їх, генерувала знову, і робила це щодня. Датасет також мав політику «снепшоти щогодини, зберігати 30 днів», скопійовану з більш стабільного навантаження. Живе дерево було помірним; снапшоти були фактично археологічним записом виходів збірки.

Негайна помилка не була в тому, що «снапшоти існують». Помилка була в припущенні, що du вимірює те саме, що й споживання пулу. Вивід du проєкту був правдивим щодо «що є зараз». Він був неактуальним щодо «які блоки пул повинен утримувати».

Ми не видалили всі снапшоти; так ви заробляєте ворогів. Ми змінили політику зберігання для того датасету відповідно до його профілю змін, потім створили окремий датасет для артефактів із коротшою політикою тримання і без довготривалих снапшотів. Нарахування перестало бути предметом суперечок, бо числа стали узгоджуватися з намірами.

Дія постмортему, яка справді мала значення: кожному датасету присвоїли явний клас даних (епhemeral build artifacts, user home directories, databases, VM images) і політики снапшотів прив’язали до класу, а не до настрою.

Міні-історія 2: Оптимізація, що обернулась проти

Команда, орієнтована на продуктивність, ввімкнула агресивне стиснення та налаштування recordsize по змішаному навантаженню датасету. Їхні бенчмарки виглядали чудово: менше дискового I/O, більше попадань у кеш, краща пропускна здатність. Вони розгорнули це широко і оголосили перемогу.

Потім вікна резервного копіювання почали відставати. Не тому, що ZFS став повільнішим, а тому, що снапшоти почали утримувати набагато більше унікальних блоків, ніж очікували. Навантаження містило великі файли, які часто модифікувалися в невеликих ділянках. Вибір recordsize, який «пасував для послідовної пропускної здатності», збільшив write amplification для випадкових оновлень. Кожна мала зміна спричиняла більше блочного зміщення, яке снапшоти охоче зберігали. Фізичне використання росло швидше, ніж хто-небудь моделював.

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

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

Міні-історія 3: Нудна, але правильна практика, що врятувала день

Інша організація мала сумне правило: кожен датасет мусив мати щомісячний звіт «облік простору» включно з usedbydataset, usedbysnapshots і списком топ-споживачів снапшотів. Люди скаржилися, що це паперова робота. Це не була паперова робота; це була розвідка.

Одного кварталу пул почав рухатися до 85% попри стабільні бізнес-метрики. Ніхто не панікував, бо щомісячні звіти показали зміщення: usedbysnapshots росло, а usedbydataset — ні. Це не «більше даних»; це «більше історії на одиницю даних», що зазвичай означає підвищений churn або зміну утримання.

Вони виявили це рано: додаток перейшов від додавання логів до періодичного переписування великого файлу стану, що різко підвищило churn. Оскільки команда вже стежила за простором снапшотів як метрикою першого порядку, вони змогли відреагувати до того, як пул досягне критичної межі.

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

Практичні завдання: команди та інтерпретація

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

Завдання 1: Отримати правдиву розбивку датасету (usedby*)

cr0x@server:~$ zfs list -o name,used,refer,usedbydataset,usedbysnapshots,usedbychildren,usedbyrefreservation tank/proj
NAME        USED  REFER  USEDBYDATASET  USEDBYSNAPSHOTS  USEDBYCHILDREN  USEDBYREFRESERV
tank/proj  3.40T  1.95T         1.80T            1.55T            50.0G                 0B

Інтерпретація: Розбіжність видно прямо тут: снапшоти відповідають за 1.55T. du переважно відображає ~1.8T живого датасету (плюс-мінус стиснення/метадані), а не історію снапшотів.

Завдання 2: Порівняти «виділено» і «очевидний» розміри в du

cr0x@server:~$ du -sh /tank/proj
1.9T    /tank/proj
cr0x@server:~$ du -sh --apparent-size /tank/proj
2.6T    /tank/proj

Інтерпретація: За замовчуванням du ближче до виділених блоків; apparent size — це логічні розміри файлів. Якщо увімкнено стиснення, логічний може бути значно більшим за фізичний.

Завдання 3: Перевірити коефіцієнт стиснення і логічний простір на рівні датасету

cr0x@server:~$ zfs get -o name,property,value -H compressratio,compression,logicalused,logicalreferenced tank/proj
tank/proj	compressratio	1.37x
tank/proj	compression	lz4
tank/proj	logicalused	4.65T
tank/proj	logicalreferenced	2.70T

Інтерпретація: Логічні байти вищі за фізичні. Якщо хтось порівнює логічні підсумки з фізичним використанням пулу, у вас буде суперечка замість плану.

Завдання 4: Перелічити снапшоти і знайти «дорогі»

cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -s used tank/proj
NAME                     USED  REFER  CREATION
tank/proj@daily-2025-12-01 120G  1.95T  Mon Dec  1 00:00 2025
tank/proj@daily-2025-11-30 118G  1.95T  Sun Nov 30 00:00 2025
tank/proj@hourly-2025-12-24-23  22G  1.95T  Wed Dec 24 23:00 2025

Інтерпретація: USED для снапшоту — це «унікальний простір, приписаний цьому снапшоту» (зміни з попереднього снапшоту в цьому лінійці). Великі числа вказують на великий churn у цей інтервал.

Завдання 5: Знайти сигнал «записано з моменту снапшоту» (чудово показує churn)

cr0x@server:~$ zfs get -H -o name,property,value written tank/proj
tank/proj	written	0B
cr0x@server:~$ zfs snapshot tank/proj@now
cr0x@server:~$ zfs get -H -o name,property,value written tank/proj
tank/proj	written	18.4G

Інтерпретація: written — це скільки даних записано з моменту останнього снапшоту. Якщо це багато щогодини, довге зберігання буде дорогим.

Завдання 6: Підтвердити, чи видимі .zfs снапшоти і чи йде du по них

cr0x@server:~$ zfs get -H -o value snapdir tank/proj
hidden
cr0x@server:~$ ls -la /tank/proj/.zfs
ls: cannot access '/tank/proj/.zfs': No such file or directory

Інтерпретація: Якщо snapdir=visible, необережний du може пройтися по снапшотах і «подвійно порахувати» з людської точки зору. Якщо він прихований, du зовсім ігноруватиме снапшоти.

Завдання 7: Шукати резервації та refreservations

cr0x@server:~$ zfs get -H -o name,property,value reservation,refreservation tank/proj
tank/proj	reservation	0B
tank/proj	refreservation	500G

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

Завдання 8: Інспектувати квоти і refquotas (чому AVAIL виглядає неправильно)

cr0x@server:~$ zfs get -H -o name,property,value quota,refquota,avail,used tank/proj
tank/proj	quota	2T
tank/proj	refquota	none
tank/proj	avail	120G
tank/proj	used	1.88T

Інтерпретація: Навіть якщо в пулі є вільне місце, квота обмежує зростання. Люди часто плутають це з «таємничим зникненням ємності». Це політика, що виконує свою роботу.

Завдання 9: Перевірити здоров’я пулу і реальність slop-space через zpool list

cr0x@server:~$ zpool list -o name,size,alloc,free,capacity,health tank
NAME   SIZE  ALLOC   FREE  CAPACITY  HEALTH
tank  20.0T  17.2T  2.80T       86%  ONLINE

Інтерпретація: При ~86% заповнення ви в зоні, де фрагментація і поведінка алокації можуть стати проблемними. Також очікуйте, що zfs list AVAIL буде меншим за «FREE» через slop space і обмеження на рівні датасету.

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

cr0x@server:~$ zfs list -o name,used,usedbydataset,usedbysnapshots -r tank | head
NAME            USED  USEDBYDATASET  USEDBYSNAPSHOTS
tank           17.2T         2.10T           14.7T
tank/proj       3.40T         1.80T            1.55T
tank/vm         8.90T         2.40T            6.30T
tank/home       2.10T         1.95T             120G

Інтерпретація: Коли usedbysnapshots домінує, пул платить за історію. Це може бути правильно — але це має бути свідомим.

Завдання 11: Помітити «видалено, але все ще використовується» простір: відкриті дескриптори файлів

cr0x@server:~$ sudo lsof +L1 | head
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NLINK   NODE NAME
java     2114 app   123w   REG  0,119  1048576     0 912345 /tank/proj/logs/app.log (deleted)

Інтерпретація: Це не специфічно для ZFS, але частий винуватець. Файл видалено, du його не рахує, але простір залишається виділеним, поки процес не закриє дескриптор.

Завдання 12: Оцінити тиск дрібних файлів і дерева, багаті на метадані

cr0x@server:~$ find /tank/proj -xdev -type f -size -16k | wc -l
4821931
cr0x@server:~$ du -sh /tank/proj
1.9T    /tank/proj

Інтерпретація: Мільйони дрібних файлів означають накладні витрати метаданих і потенційний тиск на спеціальний vdev (якщо налаштований). Якщо ваші «дані» малі, але кількість файлів велика, очікуйте, що пул поведеться інакше, ніж при роботі з великими файлами.

Завдання 13: Перевірити вибір recordsize і volblocksize (підказки про write amplification)

cr0x@server:~$ zfs get -H -o name,property,value recordsize tank/proj
tank/proj	recordsize	1M
cr0x@server:~$ zfs get -H -o name,property,value volblocksize tank/vm/zvol01
tank/vm/zvol01	volblocksize	128K

Інтерпретація: Великий recordsize може бути відмінним для потокового IO, але може підвищити витрати при churn під снапшотами для випадкових оновлень. volblocksize для zvol має схожий вплив.

Завдання 14: Виявити властивість copies, що множить використання

cr0x@server:~$ zfs get -H -o name,property,value copies tank/proj
tank/proj	copies	2

Інтерпретація: Ви платите вдвічі за блоки даних (плюс метадані). Якщо ніхто цього не планував, це чисте пояснення «чому ZFS більше, ніж du».

Завдання 15: Показати вплив refreservation саме на referenced space

cr0x@server:~$ zfs list -o name,refer,usedbyrefreservation tank/proj
NAME        REFER  USEDBYREFRESERV
tank/proj  1.95T             500G

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

Плейбук швидкої діагностики

Це «у мене є 10 хвилин до дзвінка з рев’ю ємності» плейбук. Він не вирішить усе, але підкаже, в якому напрямку бігти.

Перший крок: визначити, чи невідповідність через снапшоти, резервації чи щось інше

cr0x@server:~$ zfs list -o name,used,refer,usedbydataset,usedbysnapshots,usedbyrefreservation tank/target
NAME         USED  REFER  USEDBYDATASET  USEDBYSNAPSHOTS  USEDBYREFRESERV
tank/target  3.4T  1.9T         1.8T            1.6T               0B

Як інтерпретувати:
Якщо usedbysnapshots великий: це утримання історії + churn.
Якщо usedbyrefreservation великий: це політика/резервація.
Якщо usedbydataset великий, але du малий: підозрюйте відкриті, але видалені файли, спеціальні випадки як copies, або що du обходить не ту точку монтування.

Другий крок: перевірити, чи du вимірює логічне або фізичне, і чи переходить він кордони

cr0x@server:~$ du -sh /tank/target
cr0x@server:~$ du -sh --apparent-size /tank/target
cr0x@server:~$ mount | grep 'tank/target'

Що ви дізнаєтесь: чи порівнюєте виділені vs очевидні байти, і чи шлях, який ви скануєте, дійсно є тим датасетом, який ви думаєте.

Третій крок: ідентифікувати швидкість churn і політику зберігання снапшотів

cr0x@server:~$ zfs get -H -o name,property,value written,com.sun:auto-snapshot tank/target
tank/target	written	220G
tank/target	com.sun:auto-snapshot	true

Що ви дізнаєтесь: Якщо written стрибає на сотні гігабайт за інтервал, довге зберігання снапшотів домінуватиме у фізичному використанні.

Четвертий крок: підтвердити заповненість пулу і чи ви в зоні «практично повно»

cr0x@server:~$ zpool list -o name,alloc,free,capacity tank
NAME   ALLOC  FREE  CAPACITY
tank  17.2T  2.8T       86%

Що ви дізнаєтесь: При високому заповненні все ускладнюється: вивільнення не відображається швидко (бо їх тримають снапшоти), алокації фрагментуються, продуктивність може падати, і «AVAIL» стає політичним питанням.

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

Помилка 1: Використовувати zfs list USED як «розмір живих даних»

Симптом: USED датасету величезний, але du менший, і команди додатків запевняють, що нічого не змінювалося.
Причина: USED включає простір, на який посилаються снапшоти (і потенційно резервації).
Виправлення: Використовуйте usedbydataset для живих даних і usedbysnapshots для історії; налаштуйте політику зберігання снапшотів або поведінку churn.

Помилка 2: Вважати, що видалені файли одразу звільняють простір

Симптом: rm -rf виконується, du падає, але простір пулу не відновлюється.
Причина: Снапшоти все ще посилаються на ті блоки; або процес все ще тримає файл відкритим (deleted-but-open).
Виправлення: Перевірте споживачів снапшотів; запустіть lsof +L1; перезапустіть/перевірте logrotate процеси; цілеспрямовано видаліть снапшоти.

Помилка 3: Порівнювати du –apparent-size з zfs USED

Симптом: du --apparent-size каже 10T, ZFS каже 4T; хтось називає це «зниклими даними».
Причина: Стиснення (і іноді розріджені файли) зменшують фізичне використання.
Виправлення: Визначте, чи вам потрібен логічний або фізичний облік. Використовуйте logicalused разом з used і чітко підписуйте графіки.

Помилка 4: Ігнорувати refreservation і потім дивуватися, куди пішла ємність

Симптом: Вільне місце пулу зменшується швидше, ніж росте живі дані; AVAIL скрізь виглядає низьким.
Причина: refreservation закріплює простір, навіть якщо ним не користуються файли.
Виправлення: Аудитуйте refreservation/reservation по датасетах; видаліть або правильно підберіть розмір. Залишайте резервації для критичних сервісів, що потребують гарантованого запасу.

Помилка 5: Снапшотувати високочастотні VM образи як домашні каталоги

Симптом: Простір снапшотів росте вибухоподібно; відкат працює чудово, але ємність — ні.
Причина: Випадкові записи + COW + часті снапшоти = багато унікальних блоків, що утримуються.
Виправлення: Налаштуйте частоту/тривалість зберігання снапшотів; розгляньте частоту реплікації; виділіть окремі датасети для ВМ; переконайтеся, що recordsize/volblocksize відповідають IO-патерну.

Помилка 6: copies=2 ввімкнено «тимчасово» і забуто

Симптом: Використаний простір приблизно вдвічі більший, ніж очікується; у снапшотах нічого не знайдено.
Причина: Властивість copies дублює блоки.
Виправлення: Аудитуйте zfs get copies -r. Якщо видаляти, зрозумійте, що зміна впливає на нові записи; існуючі блоки можуть залишатися, поки не будуть перезаписані.

Помилка 7: Працювати з пулом занадто повним, потім називати це багом ємності

Симптом: Записи сповільнюються, вивільнення не допомагає, помилки алокації близько до «ще є трохи вільного».
Причина: Висока фрагментація + slop space + обмеження metaslab.
Виправлення: Тримайте пули нижче здорового порогу (багато команд орієнтуються нижче ~80% для загальних навантажень). Розширюйте ємність або мігруйте дані до того, як досягнете обриву.

Чеклісти / покроковий план

Чекліст: «du менший за zfs list USED» (найпоширеніше)

  1. Запустіть zfs list -o usedbydataset,usedbysnapshots,usedbyrefreservation для датасету.
  2. Якщо usedbysnapshots великий, перелічіть снапшоти, відсортовані за used, і визначте політику зберігання.
  3. Перевірте швидкість churn за допомогою zfs get written між інтервалами снапшотів.
  4. Підтвердьте, що ніхто випадково не робить снапшотів занадто часто (автоматизація, cron, оркестраційні інструменти).
  5. Перевірте відкриті, але видалені файли за допомогою lsof +L1.
  6. Вирішіть: змінити утримання, змінити поведінку churn чи купити місце. Не «видаляйте випадкові снапшоти» без розуміння реплікації/бекап-залежностей.

Чекліст: «zfs list REFER менший за du»

  1. Перевірте, чи ви використовували du --apparent-size (логічне), тоді як REFER — фізичне.
  2. Перевірте налаштування стиснення і compressratio.
  3. Для розріджених файлів порівняйте логічний розмір з ls -l і виділений з du.
  4. Переконайтеся, що du не переходить через точки монтування або не сканує інший шлях, ніж монтування датасету.

Чекліст: «AVAIL набагато менше за pool free»

  1. Перевірте quota/refquota та reservation/refreservation датасету.
  2. Перевірте заповненість пулу (zpool list) і врахуйте поведінку slop space.
  3. Пошукайте інші датасети з великими резерваціями, що закріплюють ємність.
  4. Якщо пул майже повний, перестаньте вважати «FREE» за доступний; плануйте розширення/міграцію.

Часті питання (FAQ)

1) Яке число мені довіряти: du чи zfs list?

Довіряйте тому, що відповідає на ваше питання. Для «який розмір живого дерева директорій» використовуйте du (виділене) або du --apparent-size (логічне). Для «яка частина ємності пулу спожита» використовуйте фізичний облік ZFS (zfs list плюс розбивка usedby*).

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

Тому що снапшоти зберігають старі блоки. Видалення видаляє лише живу посилання. Простір повертається, коли жоден снапшот (і жоден клон) не посилається на ці блоки. Також перевіряйте видалені, але відкриті файли за допомогою lsof +L1.

3) Що означає zfs list REFER?

REFER — це кількість фізичного простору, на яку посилається сам датасет (не його нащадки). Це ближче до «живого виду», ніж USED, але все одно не співпаде з du --apparent-size на стиснених датасетах.

4) Що насправді означає «USED» у снапшоті?

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

5) Чому AVAIL менше за zpool FREE?

Бо AVAIL обмежений квотами/резерваціями датасету і поведінкою пулу (включно зі slop space). ZFS навмисно консервативний біля повних пулів.

6) Чи може du бути більшим за zfs list?

Так, якщо ви використовуєте du --apparent-size (логічні розміри) на стисненому датасеті, або коли розріджені файли мають величезний логічний розмір. Фізичне використання ZFS може бути значно меншим.

7) Як знайти, що споживає простір снапшотів?

Почніть з виявлення датасетів, де usedbysnapshots високий, потім перелічіть снапшоти, відсортовані за used. Далі виміряйте churn за допомогою written за інтервал снапшотів. Нарешті, корелюйте з змінами навантаження (чарж ВМ, обслуговування БД, патерни CI артефактів).

8) Чи робить стиснення снапшоти дешевшими чи дорожчими?

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

9) Чи є резервації «втраченим простором»?

Це зарезервований простір — ємність, утримана, щоб датасет міг писати під час конкуренції. Це не марна витрата, якщо це запобігає аваріям у критичних сервісах. Це марна витрата, якщо ви встановили це і забули для всього підряд.

10) Чи безпечно просто видалити снапшоти, щоб отримати місце?

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

Висновок

du і zfs list не збігаються, бо вимірюють різні реальності: живі файли, досяжні зараз, проти володіння блоками пулу в часі з урахуванням політик і метаданих. ZFS не брешe; воно розповідає вам про історію, обіцянки (резервації) і фізику (стиснення, розміри блоків, накладні витрати).

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

← Попередня
WireGuard: найпростіше налаштування клієнта на Windows/macOS/Linux (та звичні підводні камені)
Наступна →
Docker «bind: address already in use»: знайдіть процес і виправте акуратно

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