ZFS refquota: єдина квота, яка зупиняє «брехні про використаний простір»

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

ZFS — це файлова система, яка каже правду — за винятком випадків, коли вона цього не робить. Не тому, що вона має баги, а тому що ZFS веде облік на дереві родини: datasets, snapshots, clones, holds, reservations, спеціальні vdev-и та метадані, які ви не усвідомлювали як такі, що тарифікуються. Якщо ви коли-небудь дивилися на числа USED, які не відповідають реальності, ви стикалися з «брехнями про використаний простір». Вони не злісні. Вони просто технічно точні в такий спосіб, що все одно змусять вас вийти на виклик о 02:00.

refquota — це квота, яка прив’язує оплату до dataset, що її створив, замість того, щоб дозволяти її соціалізуватися серед нащадків і спільної історії snapshot-ів. Якщо ви використовуєте ZFS у мультиорендній моделі (зберігання для VM, домашні директорії, CI-кеші, контейнери, цілі резервного копіювання), refquota — це єдина квота, яка послідовно зупиняє суперечки «я не використовував цей простір» від переростання в інцидент зі сховищем.

Проблема: «брехні про використаний простір» в ZFS

Давайте точно назвемо ворога. Коли люди скаржаться, що ZFS брешуть про використаний простір, вони зазвичай мають на увазі одне з наступного:

  • Dataset показує низьке використання, але пул повний.
  • Орендар стверджує, що використав лише 200G, але пул втратив 2T.
  • Видалення файлів не звільняє простір (бо snapshot-и тримають блоки живими).
  • Клони виглядають як ніби використовують «нічого» до моменту відхилення, а потім рахунок приходить неочікувано.
  • Квота у батька виглядає нормальною, але діти все одно можуть викликати виснаження пулу через спільну історію snapshot-ів.

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

Класичні квоти (quota) стосуються загального простору, який використовує dataset і його нащадки. Вони чудові для «ця піддерева не повинна перевищувати X». Але вони не призначені для справедливого нарахування тільки власних змін цього dataset, коли snapshot-и/клони/нащадки діляться блоками. Саме для цього існує refquota: він обмежує referenced space саме цього dataset.

Одне речення, яке можна взяти на нараду: quota — це сімейний бюджет; refquota — це персональний кредитний ліміт.

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

Чому команди експлуатації отримують опіки

Збої в операціях навколо місця в ZFS рідко пов’язані з незнанням команд. Вони пов’язані з припущенням моделі, яка не є правдивою:

  • Припущення, що видалення файлу негайно звільняє простір.
  • Припущення, що USED dataset — це те, «скільки він коштує» пулу прямо зараз.
  • Припущення, що квоти працюють як проектні квоти ext4 або XFS.
  • Припущення, що snapshot-и «безкоштовні поки вони не виростуть». Вони безкоштовні, поки ви не зміните блоки.

refquota не робить snapshot-и безкоштовними. Воно обмежує dataset від розростання його referenced відбитку понад ліміт — навіть коли використання важко зрозуміти через спільну історію. Воно змушує відповісти на просте питання: «Якого розміру цей dataset може бути, незалежно від усього?»

Цікаві факти та історичний контекст

Кілька контекстних пунктів, що важливі при проєктуванні політики та прогнозуванні поведінки:

  1. Основна одиниця обліку ZFS — це вказівник на блок, а не ім’я файлу. Саме тому snapshot-и можуть тримати простір живим без «файлів», які ви бачите.
  2. Snapshot-и не є копіями. Вони — незмінні посилання на існуючі блоки і «коштують» простір лише в міру відхилення живого dataset від них.
  3. Клони — це записувані snapshot-и. Вони ділять блоки з джерелом, і ваш рахунок залежить від того, наскільки вони відійшли від спільної історії.
  4. «USED» — це багаторівневий метрік. Він охоплює простір, на який посилається dataset, плюс простір, на який посилаються діти і snapshot-и залежно від того, яку властивість ви читаєте (used, refer, usedby*).
  5. ZFS має окремі поняття «логічного» і «фізичного» простору. Стиснення і копії означають, що логічний розмір dataset може сильно відрізнятися від виділеного пулом простору.
  6. Квоти в ZFS еволюціонували відповідно до моделі dataset, а не POSIX користувацьких квот. Вони в першу чергу обмежують datasets; користувацькі/групові квоти — це додатковий шар.
  7. «Referenced» — найближче до фактографічного сліду для виставлення рахунків. Воно наближено показує, що було б звільнено, якби ви видалили dataset (не рахуючи блоків, які все ще потрібні іншим).
  8. Резервації можуть спричинити «таємничий» ENOSPC. Пул з достатнім сирим простором все одно може відмовити у записі, якщо вільний простір недоступний для конкретного dataset через reservations і квоти.
  9. Історично багато інцидентів ZFS пов’язані з політикою збереження snapshot-ів, а не швидкістю запису. Люди розраховують на щоденний обіг і забувають, що «щотижня зберігати рік» нарощується.

Сімейство квот: quota, refquota, reservation, refreservation

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

quota

quota обмежує кількість простору, яку dataset та всі його нащадки можуть використовувати. Якщо ви встановите quota=1T на tank/prod, то tank/prod плюс tank/prod/db плюс tank/prod/vm разом не повинні перевищувати 1T.

Використовуйте його, коли хочете жорстку межу для піддерева.

refquota

refquota обмежує кількість простору, на яку посилається сам dataset (його «персональний відбиток»), виключаючи нащадків. Це та, що поводиться як «обмежити цей dataset, незалежно від того, що роблять його діти».

Використовуйте її для dataset-ів орендарів, дисків VM, коренів контейнерів, домашніх директорій — всього, де потрібні індивідуальні ліміти, які не перетворюються на суперечки через спільні snapshot-и.

reservation

reservation гарантує простір для dataset та всіх його нащадків. Це обіцянка «це піддерево завжди матиме принаймні X доступного простору».

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

refreservation

refreservation гарантує простір для самого dataset (виключаючи нащадків). Це персональна версія reservation, так само як refquota — персональна версія quota.

Використовуйте її, коли dataset потребує гарантованого запасу для сплесків, росту метаданих або транзакційних піків (бази даних, WAL, деякі шаблони VM). Але ставтесь до неї як до бюджетного розподілу: вона зменшує «вільний для всіх» простір пулу.

Коротка ментальна модель

Якщо запам’ятати лише одне:

  • quota: обмежити сім’ю.
  • refquota: обмежити людину.
  • reservation: гарантувати сім’ю.
  • refreservation: гарантувати людину.

Як refquota насправді працює (і чого вона не робить)

Referenced vs used: рахунок, який ви можете відстояти

Властивість, що тут має значення — це referenced (часто показується як REFER у zfs list). Це кількість простору, яка була б звільнена, якби dataset був знищений, виключаючи блоки, на які все ще посилаються інші об’єкти (наприклад snapshot-и за межами власного набору snapshot-ів або клони, що залежать від відносин).

refquota застосовується до referenced-простору dataset. Коли ви встановлюєте refquota, ZFS припиняє запис, коли referenced-простір цього dataset перевищить ліміт.

Це має дві операційні наслідки:

  • Воно надає пер-дataset «знак стоп», який не розширюється просто тому, що існує дочірній dataset.
  • Воно не запобігає заповненню пулу через snapshot-и, що утримуються в інших місцях або через інші dataset-и. Це не захист на рівні пулу; це інструмент справедливості.

Чого refquota не вирішує

refquota не врятує вас від:

  • Фрагментації пулу та необхідності запасу (slop space). ZFS потребує робочого простору. Якщо ви тримаєте пули заповненими, у вас виникнуть проблеми з продуктивністю і дивні шаблони ENOSPC незалежно від квот.
  • Вибуху накопичення snapshot-ів. Dataset може залишатися в межах свого refquota, тоді як старі snapshot-и утримують величезну кількість простору на рівні пулу. Dataset «не бачить» цей рахунок як власне referenced-використання, якщо блоки приписані інакше.
  • Цілей реплікації без узгодженої політики. Потік send/receive може відтворити snapshot-и і холди, які зроблять використання відмінним від джерела, якщо ви не будете обережні з retention і холдами.

Друга жарта, бо вона вам знадобиться, коли графік пішов вертикально: refquota — це як обмежувач швидкості на вантажівці — він не зупинить вас від в’їзду в річку, але зупинить вас від звинувачення двигуна пізніше.

Чому тільки quota веде до «брехень про використаний простір»

Через snapshot-и і клони питання «хто використав простір» стає питанням володіння блоками. Стандартний quota базується на піддереві і взаємодіє з нащадками. Якщо ваша структура орендарів — «один батьківський dataset з багатьма дітьми», quota на батькові може бути формально правильною, але операційно марною для білінгу та контролю зони ураження.

Ось шаблон, який боляче б’є:

  • Ви встановлюєте quota на tank/tenants.
  • Кожен орендар — дочірній dataset tank/tenants/acme, tank/tenants/zephyr тощо.
  • Snapshot-и робляться на батькові або реплікуються так, що перетинають очікування.
  • Один орендар інтенсивно змінює дані; snapshot-и утримують старі блоки.
  • Пул заповнюється, але dataset орендаря здається «малим», залежно від метрики, яку ви дивитесь.

refquota на кожному dataset орендаря змінює дискусію з «простір складний» на «ви досягли ліміту; очистіть або купіть більше».

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

1) Інцидент від неправильного припущення: «Видалення файлів звільняє простір»

Налаштування було звичним: спільний ZFS-пул для флоту CI-runner-ів і кількох ефермерних кешів збірки. Кожна команда отримала dataset, а платформа встановила quota на батьківський dataset. Snapshot-и робилися щогодини, бо колись хтось втратив кеш і оголосив війну втратам даних.

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

Чому? Snapshot-и. Snapshot-и тримали старі блоки, тож видалення живих файлів їх не звільнило. Але більша операційна помилка полягала в припущенні, що квоти dataset-ів запобігатимуть одному складу впливати на всіх. Вони цього не робили, бо quota стояла на батьківському піддереві, а облік, за яким вони дивились, був USED з zfs list, а не оглядом, що враховує snapshot-и.

Виправлення не було героїчним. Воно було нудним і правильним: per-team refquota, плюс політика збереження, що відповідала фактичному випадку використання (щогодинні snapshot-и на 24 години, щоденні на тиждень, а не «щогодинно назавжди»). Після цього, коли команда стикалася з обмеженням, це була її власна стіна. Пул перестав бути спільною трагедією.

2) Оптимізація, що обернулася проти: «Клони щоб зекономити місце»

Команда віртуалізації хотіла швидше створювати dev VM. У них були golden images. Вони виявили ZFS-клони і вирішили використовувати їх скрізь: створити snapshot шаблону, клонувати для кожної VM і насолоджуватися миттєвим створенням і спільними блоками.

Деякий час було чудово. Зростання зберігання сповільнилося, час деплою покращився, а панель виглядала здоровою. Потім настала патч-ніч. Усі застосували оновлення ОС по десятках VM, і напади записів вибухнули. Відхилення від базового образу означало, що кожна VM почала виділяти власні блоки. Це нормально, але сюрприз прийшов з людського боку: команди припускали, що «шаблон спільний, отже майже безкоштовний», і ніхто не встановив refquota на кожну VM.

Пул досяг порогу, де продуктивність деградувала. Не просто «повільніше», а «операції з метаданими виконуються, наче голубами». Команда спробувала пом’якшити ситуацію, видаляючи VM, але деякі важкі блоки все ще були посиланнями через клонування і відносини snapshot-ів. Простір не повернувся туди, де вони очікували. Вони дивилися на неправильні метрики.

Відновлення включало дві зміні політики: (1) помістити кожну VM dataset під refquota, погоджений з її призначеним розміром, і (2) розглядати клони як інструмент провізування, а не стратегію життєвого циклу — піднімати клон у разі потреби і не тримати складний ланцюг залежностей місяцями. Оптимізація не була помилкою; їй просто бракувало запобіжних бар’єрів.

3) Нудна, але правильна практика, що врятувала день: «Бюджети простору + щотижневі аудити»

Інший магазин керував мультиорендним ZFS-пристроєм для внутрішніх команд. Нічого особливого: передбачувані розклади snapshot-ів, послідовна номенклатура та невеликий щотижневий ритуал. Кожного понеділка інженер витрачав 15 хвилин на перегляд короткого звіту: топ dataset-ів по usedbysnapshots, топ по referenced, dataset-и, що наближаються до refquota, і пули з менше ніж 20% вільного.

Ця практика здавалася зайвою — допоки інтеграція з постачальником не почала скидати великі, стисувані логи в неправильний dataset. Стиснення робило логічний розмір страшним, але фізичне виділення залишалося помірним… поки не перестало. Ротація логів щодня оновлювала блоки, а snapshot-и зберігали старі версії. Тренд пулу почав підніматися.

Понеділковий аудит спіймав це до того, як це стало інцидентом. Команда побачила dataset з швидко зростаючим usedbysnapshots і refquota, що наближався до ліміту. Вони виправили шлях інжекції, обнулили snapshot-и тільки для цього dataset-а і трохи збільшили refquota, щоб не зламати критичний пайплайн, поки зміни розгортались.

Жодного нічного виклику. Жодного термінового розширення. Просто невелика, нудна звичка і квоти, що означали те, що вони думали. У продакшені нудність — це функція.

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

Це завдання, які ви можете виконати сьогодні. Кожне включає, на що звертати увагу і як інтерпретувати результати. Приклади припускають пул з іменем tank.

Завдання 1: Побачити правду: used vs referenced

cr0x@server:~$ zfs list -o name,used,refer,usedbysnapshots,usedbychildren,usedbydataset -r tank
NAME                      USED  REFER  USEDBYSNAPSHOTS  USEDBYCHILDREN  USEDBYDATASET
tank                     3.12T   192K             0B            3.12T            192K
tank/tenants             3.12T   128K           540G            2.58T            128K
tank/tenants/acme         900G   600G           220G             80G            600G
tank/tenants/zephyr       780G   760G            10G             10G            760G

Інтерпретація: USED включає snapshot-и і дітей. REFER — це «персональний відбиток» dataset. Якщо орендар каже «Я тільки 600G», перевірте, чи snapshot-и утримують 220G і чи діти використовують більше.

Завдання 2: Перевірити quotas і refquotas одразу

cr0x@server:~$ zfs get -o name,property,value,source quota,refquota,reservation,refreservation tank/tenants/acme
NAME               PROPERTY        VALUE  SOURCE
tank/tenants/acme  quota           none   default
tank/tenants/acme  refquota        700G   local
tank/tenants/acme  reservation     none   default
tank/tenants/acme  refreservation  none   default

Інтерпретація: Якщо refquota встановлено, а quota — ні, ви впроваджуєте пер-дataset обмеження без обмеження нащадків. Це часто правильно для dataset-ів орендарів, яких не слід карати за дочірні dataset-и (або які їх не використовують).

Завдання 3: Безпечно встановити refquota (і підтвердити)

cr0x@server:~$ sudo zfs set refquota=500G tank/tenants/acme
cr0x@server:~$ zfs get -o name,property,value refquota tank/tenants/acme
NAME               PROPERTY  VALUE  SOURCE
tank/tenants/acme  refquota  500G   local

Інтерпретація: Записи до tank/tenants/acme зупиняться, коли REFER досягне приблизно 500G (з урахуванням recordsize, метаданих, slop space). Це «знак стоп».

Завдання 4: Симулювати «чому моє видалення не звільнило простір?»

cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -s creation tank/tenants/acme
NAME                              USED  REFER  CREATION
tank/tenants/acme@hourly-2025...   24G   600G  Mon Dec 23 01:00 2025
tank/tenants/acme@hourly-2025...   30G   620G  Mon Dec 23 02:00 2025

Інтерпретація: USED snapshot-а — це скільки унікального простору той snapshot утримує в порівнянні з поточним станом dataset. Якщо USED snapshot-а великий, видалення не звільнить багато, поки snapshot-и не закінчаться або не будуть знищені.

Завдання 5: Знайти dataset-и, що наближаються до refquota

cr0x@server:~$ zfs list -o name,refer,refquota -r tank/tenants
NAME                REFER  REFQUOTA
tank/tenants         128K      none
tank/tenants/acme    498G      500G
tank/tenants/zephyr  310G      800G

Інтерпретація: acme майже досягне жорсткої зупинки. Очікуйте помилок додатків скоро (збої запису), а не м’якого попередження.

Завдання 6: Діагностувати ENOSPC: перевірити стан пулу і вільний простір

cr0x@server:~$ zpool list -o name,size,alloc,free,cap,health
NAME  SIZE  ALLOC  FREE  CAP  HEALTH
tank  7.25T  6.60T  660G  90%  ONLINE

Інтерпретація: 90% заповнення — це зона небезпеки для багатьох пулів, особливо з HDD vdev-ами. Навіть якщо квоти встановлені, пул може заповнюватися через snapshot-и, резервації або інші dataset-и.

Завдання 7: Показати простір, утримуваний snapshot-ами (тихий податок)

cr0x@server:~$ zfs list -o name,usedbysnapshots -r tank/tenants | sort -h -k2
tank/tenants               540G
tank/tenants/acme          220G
tank/tenants/zephyr         10G

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

Завдання 8: Ідентифікувати холди, що заважають видаленню snapshot-ів

cr0x@server:~$ zfs holds -r tank/tenants/acme@hourly-2025-12-23-0200
NAME                               TAG          TIMESTAMP
tank/tenants/acme@hourly-2025-12-23-0200  keep         Tue Dec 23 02:10 2025

Інтерпретація: Тег холда (тут keep) блокує видалення. Якщо простір не звільняється після «видалили старі snapshot-и», перевірте холди перед тим, як думати, що ZFS зачарований.

Завдання 9: Зняти hold і видалити snapshot

cr0x@server:~$ sudo zfs release keep tank/tenants/acme@hourly-2025-12-23-0200
cr0x@server:~$ sudo zfs destroy tank/tenants/acme@hourly-2025-12-23-0200

Інтерпретація: Простір не обов’язково повернеться миттєво, якщо інші snapshot-и/клони все ще посилаються на ті ж блоки, але ви зняли одну якірну точку.

Завдання 10: Аудит відносин клонів (простір, спільний по лінії)

cr0x@server:~$ zfs get -o name,property,value origin tank/vm/dev-42
NAME           PROPERTY  VALUE
tank/vm/dev-42  origin   tank/vm/template@golden-2025-12-01

Інтерпретація: Якщо dataset — клон, знищення origin snapshot-а може бути заблоковане, а облік може вас здивувати. Простір може «належати» ланцюжку залежностей.

Завдання 11: Промотувати клон, щоб розірвати залежність від origin

cr0x@server:~$ sudo zfs promote tank/vm/dev-42
cr0x@server:~$ zfs get -o name,property,value origin tank/vm/dev-42
NAME           PROPERTY  VALUE
tank/vm/dev-42  origin   -

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

Завдання 12: Підтвердити, що dataset звільнить (захисний звіт)

cr0x@server:~$ zfs get -o name,property,value referenced,logicalreferenced,used,logicalused tank/tenants/acme
NAME               PROPERTY           VALUE
tank/tenants/acme  referenced         498G
tank/tenants/acme  logicalreferenced  1.02T
tank/tenants/acme  used               900G
tank/tenants/acme  logicalused        1.60T

Інтерпретація: Стиснення (і іноді копії) робить логічні розміри більшими за фізичні. Якщо ви виставляєте рахунок, вирішіть, чи будете нараховувати за фізичне (referenced) чи логічне (logicalreferenced). Для планування ємності фізичне важливе; для «скільки у вас даних» логічне може відповідати очікуванню користувача.

Завдання 13: Спостерігати застосування (виявлення влучань refquota)

cr0x@server:~$ zfs get -o name,property,value refquota,refer tank/tenants/acme
NAME               PROPERTY  VALUE
tank/tenants/acme  refquota  500G
tank/tenants/acme  refer     498G

cr0x@server:~$ sudo -u acmeuser dd if=/dev/zero of=/tank/tenants/acme/bigfile bs=1M count=4096
dd: failed to open '/tank/tenants/acme/bigfile': Disc quota exceeded

Інтерпретація: Помилка часто буде «Disc quota exceeded» (EDQUOT), а не «No space left on device». Це добре: воно вказує на політику dataset, а не на виснаження пулу.

Завдання 14: Знайти dataset-и з резерваціями, що можуть спричинити сюрпризний ENOSPC

cr0x@server:~$ zfs get -o name,property,value -r tank reservation,refreservation | egrep -v ' none$'
tank/prod         reservation     2T
tank/prod/db      refreservation  300G

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

Швидкий план діагностики

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

1) Визначте режим помилки: EDQUOT vs ENOSPC

Перевірте журнали додатків і повідомлення ядра. Якщо ви бачите «Disc quota exceeded», ви потрапили на quota або refquota (або користувацькі/групові квоти). Якщо бачите «No space left on device», ймовірно пул вичерпано або є обмеження через reservation/slop.

cr0x@server:~$ dmesg | tail -n 20
... 

2) Перевірте спочатку ємність пулу та його стан (завжди)

cr0x@server:~$ zpool list -o name,size,alloc,free,cap,health
NAME  SIZE  ALLOC  FREE  CAP  HEALTH
tank  7.25T  6.60T  660G  90%  ONLINE

cr0x@server:~$ zpool status -x
all pools are healthy

Рішення: Якщо CAP високе (звично >80–85% на HDD-пулах, іноді нижче в залежності від навантаження), вважайте це інцидентом ємності, навіть якщо «free» є. ZFS потребує запасу для алокації і продуктивності.

3) Визначте, чи snapshot-и є справжнім споживачем

cr0x@server:~$ zfs list -o name,usedbysnapshots -r tank | sort -h -k2 | tail -n 10
tank/tenants               540G
tank/backup                1.40T

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

4) Якщо помилка EDQUOT, перевірте refquota/refer спочатку

cr0x@server:~$ zfs get -o name,property,value refquota,quota,refer,used tank/tenants/acme
NAME               PROPERTY  VALUE
tank/tenants/acme  refquota  500G
tank/tenants/acme  quota     none
tank/tenants/acme  refer     498G
tank/tenants/acme  used      900G

Рішення: Якщо refer близький до refquota, виправлення — видалити/скомпактувати дані в цьому dataset, видалити snapshot-и, що збільшують referenced-блоки (рідко, але можливо залежно від відносин клонів), або навмисно збільшити refquota.

5) Якщо помилка ENOSPC, перевірте резервації далі

cr0x@server:~$ zfs get -o name,property,value -r tank reservation,refreservation | egrep -v ' none$'
tank/prod         reservation     2T
tank/prod/db      refreservation  300G

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

6) Знайдіть топ-споживачів простору за referenced

cr0x@server:~$ zfs list -o name,refer -r tank | sort -h -k2 | tail -n 15
tank/backup/job-17     1.10T
tank/tenants/acme       498G
tank/prod/db            420G

Рішення: refer дає вам вигляд «якщо я видалю цей dataset, що я отримаю». Це швидкий спосіб ранжувати кандидати для прибирання.

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

Помилка 1: Встановили quota, коли мали на увазі refquota

Симптом: Dataset орендаря виглядає обмеженим, але дочірні dataset-и все ще можуть розростатися в неочікуваний спосіб, або обмеження застосовується до всього піддерева і викликає внутрішні конфлікти.

Виправлення: Застосуйте refquota до кожного dataset-а орендаря, що представляє рахункову одиницю. Використовуйте quota лише коли конкретно потрібне обмеження піддерева.

cr0x@server:~$ sudo zfs set refquota=200G tank/tenants/zephyr

Помилка 2: Читати USED як «що цей dataset коштує»

Симптом: Ви видаляєте дані з dataset, але його USED майже не змінюється. Або dataset виглядає великим через наявність дочірніх dataset-ів.

Виправлення: Використовуйте refer для власного відбитку dataset; використовуйте usedbysnapshots, щоб побачити податок snapshot-ів; використовуйте usedbychildren, щоб зрозуміти зростання піддерева.

Помилка 3: Не враховувати політику збереження snapshot-ів

Симптом: Пул повільно але невблаганно заповнюється, хоча активні dataset-и стабільні і «очищення» не допомагає.

Виправлення: Перевірте використання snapshot-ів і політику збереження. Видаліть холди. Настройте розклади. Розгляньте політику на рівні dataset-ів замість однієї глобальної.

Помилка 4: Ланцюги залежностей клонів, що перешкоджають очищенню

Симптом: Ви не можете знищити старий snapshot, бо «snapshot має залежні клони», або простір не повертається після видалення «великої речі».

Виправлення: Аудит відносин origin. Промотуйте клони, коли це доречно. Не залишайте клони пов’язаними з місячно-старим snapshot-ом, якщо вам не подобається археологія.

Помилка 5: Плутати фізичні і логічні розміри

Симптом: Користувачі кажуть «Я маю лише 300G даних», але ви бачите 800G логічно. Або фінанси хочуть білінг і числа не сходяться.

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

Помилка 6: Надмірне використання reservation

Симптом: Пул має вільний простір, але деякі dataset-и не можуть записати; або одне навантаження здається «неуразливим», тоді як інші голодують.

Виправлення: Проведіть аудит reservation/refreservation. Видаліть або правильно розподіліть. Використовуйте резервації економно і навмисно.

Помилка 7: Очікувати, що refquota захистить пул

Симптом: Кожен орендар має refquota, але пул все одно заповнюється і команда платформи дивується.

Виправлення: Refquota — це пер-дataset примус, а не план ємності пулу. Вам все одно потрібні цільові запаси пулу, контроль збереження snapshot-ів і моніторинг глобальних споживачів, як резервні копії.

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

Контрольний список A: Впровадження refquota для мультиорендних dataset-ів

  1. Визначте одиниці білінгу. Один dataset на орендаря/VM/container root — ідеально.
  2. Виберіть основу квоти. Фізичне (refquota на referenced) найпростіше впроваджувати; документуйте це.
  3. Встановіть refquota на кожний dataset орендаря.
  4. За бажанням встановіть батьківську quota як запобіжник. Використовуйте quota на батькові, щоб обмежити всю програму.
  5. Побудуйте політику snapshot-ів за класами даних. CI-кеші — не бази даних; не ставте їх однаково.
  6. Моніторьте dataset-и, що наближаються до ліміту. Сигналізуйте при refer/refquota > 85–90% і при швидкому зростанні usedbysnapshots.
cr0x@server:~$ sudo zfs set refquota=300G tank/tenants/acme
cr0x@server:~$ sudo zfs set refquota=500G tank/tenants/zephyr
cr0x@server:~$ sudo zfs set quota=5T tank/tenants

Контрольний список B: Відповідь на інцидент «пул заповнюється»

  1. Перевірте CAP і стан пулу (zpool list, zpool status).
  2. Ранжуйте dataset-и за usedbysnapshots і refer.
  3. Перевірте холди на великих snapshot-ах, що мали б бути видалені.
  4. Перевірте залежності клонів, що перешкоджають видаленню snapshot-ів.
  5. Налаштуйте збереження і видаляйте snapshot-и цілеспрямовано (не глобально, якщо ви не в режимі надзвичайної ситуації).
  6. Якщо пул «гарячий» (>85–90%), плануйте негайний запас: видалити, перемістити або розширити. Квоти не створять простору.

Контрольний список C: Постійна гігієна, що тримає refquota чесним

  1. Щотижневий звіт: топ usedbysnapshots, топ refer, наближені до refquota.
  2. Щомісячний перегляд reservation-ів.
  3. Перегляд життєвого циклу snapshot-ів після великих змін продукту (нові логи, нові артефакти, нова реплікація).
  4. Політика життєвого циклу шаблонів/клонів: коли промотувати, коли перебудовувати з нуля.

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

1) Чи refquota накладається на логічний чи фізичний простір?

refquota накладається на referenced-простір, як його рахує ZFS (фактично фізичне виділення після стиснення). Саме тому стиснутий dataset може вмістити більше логічних даних, ніж натякає refquota.

2) Якщо я встановлю refquota, snapshot-и все ще можуть заповнити мій пул?

Так. Snapshot-и можуть утримувати старі блоки і споживати простір пулу. Refquota обмежує, скільки живий dataset може посилатися, а не скільки історичних даних політика snapshot-ів зберігає по всьому пулу.

3) Чому dataset показує низький REFER, але високий USED?

Бо USED може включати простір snapshot-ів і дочірніх dataset-ів. REFER — це «що цей dataset сам по собі посилається». Завжди розбирайтеся з usedbydataset, usedbysnapshots і usedbychildren.

4) Яку помилку побачать додатки, коли refquota спрацює?

Зазвичай Disc quota exceeded (EDQUOT). Це підказка, що ви потрапили на обмеження dataset, а не на виснаження пулу.

5) Використовувати quota чи refquota для домашніх директорій?

Якщо кожен користувач має свій dataset, використовуйте refquota. Якщо користувачі — це директорії в одному dataset, квоти dataset-ів не допоможуть; вам потрібні користувацькі/групові квоти (інший механізм) або рефакторинг в пер-юзер datasets.

6) Чи включає refquota нащадків?

Ні. У цьому і сенс. refquota обмежує сам dataset, виключаючи дітей. Якщо ви хочете обмеження піддерева — використовуйте quota.

7) Як refquota взаємодіє з reservation?

Резервація гарантує доступний простір; refquota обмежує зростання. Ви можете мати обидва: гарантувати 50G через refreservation і обмежити 500G через refquota. Неправильне використання може створити плутану поведінку вільного простору, тож моніторьте обидва значення.

8) Чому збільшення refquota не виправило ENOSPC?

Бо ENOSPC часто означає виснаження пулу (або обмеження через reservation), а не обмеження dataset. Якщо пул зайнятий, підвищення refquota лишень змінить, хто впаде наступним.

9) Чи можна покладатися на refquota для білінгу?

Ви можете покладатися на нього для застосування і контролю зони ураження. Для білінгу вирішіть, чи нараховуєте ви за referenced фізичний простір, логічний простір або за надані ліміти. Найбільш обґрунтовано операційно — білити за застосованими лімітами (refquota) плюс виключення за перевищення.

10) Яка найпростіша політика, що працює?

Один dataset на орендаря/на навантаження, refquota на dataset, консервативна цільова величина запасу пулу і політика збереження snapshot-ів, прив’язана до бізнес-потреб — а не до паніки.

Висновок

ZFS не бреше про простір. Воно повідомляє простір так, як має робити файлова система з copy-on-write, snapshot-ами і клонуванням: блоки і посилання, а не лише файли і папки. Проблема в тому, що люди продовжують задавати ZFS питання на неправильній мові, а потім дивуються відповідям.

refquota — це квота, яка транслює блок-орієнтовану реальність ZFS у політичний кордон, який ви можете застосувати для кожного dataset. Вона не врятує пул, якщо ваша політика snapshot-ів безрозсудна, і не зробить клони «безкоштовними назавжди». Але вона припиняє найпоширеніший операційний аргумент — «цей простір не мій» — зробивши «мій» вимірюваним і застосовним. У мультиорендних середовищах це не просто зручно. Це різниця між стабільною платформою та щотижневим ритуалом звинувачень у зберіганні.

← Попередня
MySQL vs MariaDB: реплікація та відновлення після відмови — що ламається в реальному житті (і як уникнути)
Наступна →
Покинуті контейнери Docker: чому вони з’являються і як безпечно очищати

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