Ви не помічаєте внутрішньої роботи ZFS, коли все здорово. Ви помічаєте її о 02:17, коли затримки стрибають,
репліки починають тайм-аутити, і хтось питає, чи «додавання кеша» це виправить. (Не виправить. Не так.)
Це глосарій, який ви хотіли б мати до того, як зробили «просто працюючий» дизайн пулу, відправили його в продакшн
і виявили, що ваша ментальна модель була переважно відчуттями. Ми визначимо великі іменники — VDEV, TXG, ARC, SPA — а потім
використаємо їх, щоб приймати рішення, відлагоджувати вузькі місця та уникати класичних інцидентів, спричинених власними руками.
Цікаві факти та історія (те, що справді має значення)
- ZFS почалася в Sun на початку 2000-х як відповідь на безлад «файлова система + менеджер томів + RAID‑інструмент». Припущення в дизайні: стек зберігання має бути єдиною узгодженою системою.
- Copy-on-write не був новим, але ZFS зробила його операційно масовим: кожна зміна записує нові блоки, а потім атомарно змінює вказівники. Саме тому можна робити консистентні снапшоти без зупинки системи.
- Назва «Zettabyte» була амбітною у часи, коли мульти‑терабайтні пули здавалися величезними. Сьогодні це звучить не як маркетинг, а як попередження.
- OpenZFS — це спільнотне продовження після ери придбань Sun. Функції як‑от special vdevs та persistent L2ARC еволюціонували в відкритому середовищі, підштовхнуті болем реальних операторів.
- Контрольні суми для всього тоді не були типовою поведінкою в звичайних файлових системах. ZFS зробила позицію: «тиха корупція — це проблема зберігання, а не програми».
- ARC став патерном: адаптивний кеш, яким керує файлова система, який розуміє блоки, стиснення і метадані. Це не просто «RAM — кеш для диска». Це політика з власними уподобаннями.
- TXG — це компроміс між «синхронно все» і «буферизувати назавжди». Модель transaction group — причина, чому ZFS може бути швидким і консистентним — поки ваш робочий навантаження не перетворить її на затор.
- RAID‑Z — це не апаратний RAID. Парність обчислюється ZFS з урахуванням розмірів блоків і контрольних сум. Це краще в багатьох аспектах, але математика парності не безкоштовна.
- «1M recordsize» за замовчуванням не для баз даних. Це налаштування, дружнє до пропускної здатності при великих послідовних IO. Якщо ви виконуєте випадкові 8K‑записи і ніколи не міняєте це, ви не нещасливі — ви неправильно налаштовані.
Основний глосарій: VDEV, TXG, ARC, SPA (з реальними наслідками)
VDEV (віртуальний пристрій): одиниця продуктивності й відмови
VDEV — це будівельний блок ZFS для зберігання пулу. Люди буденно говорять «у мене в пулі 12 дисків»,
але ZFS чує: «у мого пулу такі‑то vdevи». І саме vdev визначає:
IOPS, латентність і часто ваш радіус ураження.
Vdev може бути одиничним диском (не робіть так), дзеркалом, RAID‑Z, файлом (не робіть цього зовсім), спеціальним vdev для метаданих,
лог‑vdev (SLOG) або пристроєм кешу (L2ARC).
Операційне правило: vdev додають продуктивність; диски всередині vdev додають стійкість (а іноді й пропускну здатність).
У пулі, що складається з кількох vdev, ZFS рівномірно розподіляє алокації між vdev. Більше vdev зазвичай означає більше паралелізму.
Але всередині RAID‑Z vdev невеликі випадкові записи платять податок парності і часто серіалізуються більше, ніж вам би хотілося.
Дзеркальні vdev — робоча конячка для навантажень, чутливих до латентності. RAID‑Z vdev — для ємності та послідовної пропускної здатності.
Якщо ви маєте змішане навантаження, обирайте усвідомлено, замість того щоб дозволяти відділу закупівель вирішувати за вас.
TXG (Transaction Group): як ZFS перетворює хаос на атомарний коміт
TXG — це пакет змін у пам’яті, які ZFS зрештою фіксує в стабільному зберіганні. Думайте про нього як
«набір брудних блоків, які ми запишемо разом і потім оголосимо стійкими».
ZFS циклічно проходить через стани TXG: open (приймає зміни), quiescing (припиняє нові зміни)
та syncing (запис на диск). Перемикання відбувається періодично та залежно від навантаження.
Якщо пул здоровий, це непомітно. Якщо пул перевантажений, ви помітите:
стрибки латентності запису, шторм синків (sync storms) і заблоковані в fsync() додатки.
Поведінка TXG — причина, чому ви можете мати високу пропускну здатність, але жахливу «хвостову» латентність. Пул може бути «зайнятий синком»,
і ваше навантаження змушене чекати. Моніторинг має розділяти «ми пишемо» і «ми заблоковані, чекаючи на завершення запису».
ARC (Adaptive Replacement Cache): ОЗП як політика, а не просто кеш
ARC — це кеш у пам’яті ZFS для часто й недавно використовуваних блоків — даних і метаданих.
Це не тупий LRU. Він адаптивний: намагається балансувати «недавні» й «часті» патерни доступу.
ARC також є політичним гравцем у вашій системі. Він конкурує з додатками за оперативну пам’ять. Якщо дозволити, ARC
із задоволенням «з’їсть» всю RAM, поки ядро не змусить його зупинитися. Це не баг; це домовленість:
пам’ять, що не використовується, — це втрачені можливості продуктивності. Але в продакшні «не використовується» трапляється рідко — ваша база даних, JVM і системний page cache теж потребують пам’яті.
ARC має кілька важливих популяцій:
MFU/MRU списки (часті/недавні),
метадані,
анонімні буфери
і брудні буфери, що очікують на TXG sync.
Коли кажуть «низький ARC hit rate», корисне уточнення: низький для якої категорії і в
SPA (Storage Pool Allocator): мозок пулу
SPA — це підсистема, що координує пул: управління vdev, алокації,
metaslab’и, карти вільного простору та високорівневий state‑машина, яка робить «пул» узгодженою сутністю.
Якби ZFS була компанією, SPA була б операційною командою, яка розпреділяє роботу.
SPA рідко трогаєте напряму, але бачите його рішення всюди: як блоки розподіляються між vdev,
як відслідковується вільний простір, чому з’являється фрагментація і чому деякі пули старіють як вино, а інші — як молоко.
Одне висловлювання, яке варто тримати на стіні, бо відмови зберігання майже завжди — це відмови координації:
«Надія — це не стратегія.»
— генерал Гордон Р. Салліван (часто цитують в інженерії та операціях)
Розширений глосарій, на який ви натрапите в продакшні
Pool
Пул — це об’єкт верхнього рівня для зберігання. Він агрегує vdev. Ви не можете зменшити його, видаливши
RAID‑Z vdev. Плануйте відповідально. Ваша майбутня версія себе не буде вражена фразою «ми просто мігруємо пізніше».
Dataset
Датасет — це файловата система з власними властивостями: compression, recordsize, quota, reservation,
sync‑поведінкою та ін. Датасети дозволяють не дати одному робочому навантаженню отруїти інше — якщо ви їх справді використовуєте.
Zvol
Zvol — це блочний пристрій, підлаштований під ZFS. Його використовують для iSCSI, дисків віртуальних машин і речей, що вимагають
блочної семантики. Налаштовуйте volblocksize під навантаження. Залиште його неправильним — відкриєте нові й захопливі способи марнувати IOPS.
Recordsize і volblocksize
recordsize — це максимальний розмір блоку для файлів в датасеті. Великий recordsize допомагає послідовній
пропускній здатності та стисненню. Малий recordsize допомагає випадковому IO і зменшує write‑ампліфікацію при малих оновленнях.
volblocksize — це розмір блоку для zvol. Він фіксується під час створення.
Якщо ви зберігаєте 8K сторінки бази даних у zvol з volblocksize 128K, ви просите ZFS виконати зайву роботу.
Metaslab
Metaslab — це ділянка простору всередині vdev, яка використовується для алокації. Фрагментація metaslab — поширена історія «мій пул на 70% заповнений і все повільно».
SPA і класи metaslab визначають, куди йдуть блоки; якщо ви близькі до заповнення, ці рішення звужуються і стають дорогими.
Scrub і resilver
Scrub перевіряє контрольні суми і ремонтує за рахунок надлишковості. Resilver відновлює надлишковість після заміни пристрою. Обидва конкурують з вашим навантаженням за IO. Тримаєте їх під контролем,
але не ігноруйте. Scrub дозволяє знайти приховані помилки, перш ніж вони стануть втратою даних.
SLOG і ZIL
ZIL — це внутрішній лог намірів у пулі для синхронних записів. SLOG — це опційний окремий пристрій журналу, щоб прискорити ці синхронні записи. SLOG не робить асинхронні записи швидшими. Він робить синхронні записи менше болючими, даючи їм низьколатентне місце для збереження.
SLOG має бути надійним і забезпечувати захист від втрати живлення. Якщо ви ставите «швидку, але крихку» флеш як SLOG, ви будуєте
брехню у вашу модель надійності. І ZFS сумлінно реалізує цю брехню.
L2ARC
L2ARC — це другий рівень кеша на швидких пристроях (звичайно SSD/NVMe). Він кешує читання, а не записи.
Історично він також коштував пам’яті для індексації; сучасні реалізації покращили поведінку, але це все одно не безкоштовно.
L2ARC не замінює достатню RAM або здорову налаштування датасетів.
Ashift
ashift — це показник розміру сектору (показник степеня двійки), який використовує ZFS для vdev. Канонічна порада для продакшну:
встановлюйте його правильно при створенні пулу, бо змінити його пізніше означає фактично «перебудувати пул».
Неправильний ashift — це повільна течія, що стає повінню під навантаженням.
Жарт №1: Неправильний ashift — це як купити взуття на розмір менше — технічно можна ходити, але ви себе ненавидітимете на сходах.
Compression
Стиснення економить місце і часто підвищує продуктивність, перетворюючи IO на CPU, а IO зазвичай є вузьким горлом.
Але якщо ваш CPU вже завантажений, стиснення може стати останньою соломинкою. Вимірюйте, перш ніж святкувати перемогу.
Copy-on-write і фрагментація
Copy-on-write означає, що блоки переписуються в інше місце, а не змінюються на місці. Це чудово для консистентності і снапшотів, але це може фрагментувати.
Фрагментація погіршується, коли пул заповнюється і коли ви часто перезаписуєте дані зі снапшотами. «ZFS повільний, коли повний» — мем, бо часто це правда в конкретних аспектах.
Практична ментальна модель: від системного виклику до диска
Читання: щасливий шлях (коли все добре)
Запит на читання приходить. ZFS перевіряє ARC. Якщо блок у ARC — все швидко. Якщо ні, ZFS планує читання з vdev,
отримує блоки, перевіряє контрольні суми, декомпресує (за потреби) і за потреби додає блок у ARC (а згодом можливо й у L2ARC).
Латентність визначається: показником кеш‑хітів, глибиною черги vdev, латентністю пристрою і тим, наскільки розкидані блоки.
Дзеркала можуть обслуговувати читання з обох сторін, часто підвищуючи паралелізм. RAID‑Z читання можуть бути нормальними, але малі випадкові читання
конкурують із розкладом парності і часто мають вищу IO‑ампліфікацію при ремонті/скрабі.
Записи: де TXG і ZIL вирішують вашу долю
Асинхронний запис потрапляє в пам’ять (брудні буфери в ARC). Пізніше TXG sync записує його на диск. Якщо система впаде до TXG sync,
ці асинхронні записи будуть втрачені. Це контракт. Додатки, яким це важливо, викликають fsync() або використовують синхронні записи.
Синхронний запис має бути зафіксований так, щоб пережити крах. ZFS використовує ZIL: він швидко логгує намір, підтверджує,
а потім пізніше TXG sync записує реальні блоки і звільняє записи журналу. Якщо у вас є SLOG, лог‑записи йдуть туди.
Якщо ні — вони потрапляють у головний пул, і ваш найповільніший vdev стає вашою латентністю синхронних записів.
Операційний висновок: латентність синхронних записів часто — це проблема лог‑пристрою і латентності пулу, а не суто пропускної здатності.
Ви можете мати 5 GB/s послідовного запису і все одно мати 20 ms fsync‑латентності, що нищить базу даних.
Управління простором: SPA, metaslab і чому «80% заповнення» — не просто цифра
SPA розбиває кожен vdev на metaslab і відслідковує вільний простір через space maps. Коли пули порожніші,
алокації дешевші: вибирається велика вільна ділянка і запис. Коли пули заповнюються і фрагментуються, алокації стають:
знайти достатньо сегментів, впоратися з розкиданими вільними екстентами, оновити метадані і заплатити більше за пошуки та облік.
Саме тому планування ємності — це планування продуктивності. Якщо ви розглядаєте «вільний простір» лише як бюджет, ZFS рано чи пізно збере свої відсотки у вигляді латентності.
Практичні завдання: команди, значення виводу та що вирішувати
Це не трюки для вечірки. Це команди, які ви виконуєте, коли хтось каже «зберігання повільне», і ви хочете
відповісти доказами, а не відчуттями.
Завдання 1: Визначити стан пулу та негайні червоні прапори
cr0x@server:~$ zpool status -v
pool: tank
state: ONLINE
scan: scrub repaired 0B in 02:14:19 with 0 errors on Wed Dec 24 03:00:12 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
/dev/disk/by-id/ata-A ONLINE 0 0 0
/dev/disk/by-id/ata-B ONLINE 0 0 0
errors: No known data errors
Що це означає: Стан і лічильники помилок показують, чи ви дебажите продуктивність, чи втрачаєте надлишковість/цілісність даних. Результати scrub важливі: repaired bytes означає, що була корупція, яку виправила надлишковість.
Рішення: Якщо ви бачите DEGRADED, зростаючі READ/WRITE/CKSUM або активний resilver,
припиняйте налаштування й починайте стабілізацію. Налагодження продуктивності — після зупинки кровотечі.
Завдання 2: Подивитися пропускну здатність і тренди латентності на рівні vdev
cr0x@server:~$ zpool iostat -v tank 1 5
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 1.20T 2.40T 320 980 45.2M 110M
mirror-0 1.20T 2.40T 320 980 45.2M 110M
ata-A - - 160 490 22.6M 55.1M
ata-B - - 160 490 22.6M 55.0M
-------------------------- ----- ----- ----- ----- ----- -----
Що це означає: Ви бачите операції та пропускну здатність по vdev і диску. Дзеркала ділять читання між сторонами;
запис іде в обидві. Якщо один диск показує значно вищу латентність у iostat -x (наступне завдання), він може тягнути вниз усе дзеркало.
Рішення: Якщо один vdev насичений (високі операції, низька пропускна здатність, зростаюча латентність), додавайте vdev (більше паралелізму)
або змінюйте характеристики навантаження (recordsize, sync‑поведінка). Якщо один диск поводиться неправильно — замініть його.
Завдання 3: Підтвердити латентність пристроїв і черги на рівні ОС
cr0x@server:~$ iostat -x 1 3
Linux 6.8.0 (server) 12/26/2025 _x86_64_ (16 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
6.20 0.00 2.10 18.40 0.00 73.30
Device r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 95.0 280.0 12.3 34.8 352.1 7.80 25.6 8.2 31.4 1.1 41.0
sdb 92.0 275.0 12.1 34.6 353.0 8.10 27.4 8.5 33.2 1.1 43.5
Що це означає: await і avgqu-sz показують латентність і глибину черги.
Високий %iowait вказує, що CPU чекає на сховище. Високий %util означає, що пристрої зайняті.
Рішення: Якщо await високий і %util завантажено, у вас обмеження по сховищу.
Якщо %iowait низький, але додатки повільні — дивіться в інші напрямки (блокування, мережа, CPU).
Завдання 4: Перевірити властивості датасету, що прямо впливають на IO
cr0x@server:~$ zfs get -o name,property,value -s local,received recordsize,compression,atime,sync,logbias tank/app
NAME PROPERTY VALUE
tank/app recordsize 128K
tank/app compression zstd
tank/app atime off
tank/app sync standard
tank/app logbias latency
Що це означає: Це ручки, що вирішують, чи ZFS робить 128K IO, стискає,
оновлює час доступу і ставиться до синхронних записів з упором на латентність.
Рішення: Для баз даних розгляньте менший recordsize (часто 16K або 8K залежно від розміру сторінки БД),
тримайте atime=off, якщо це не потрібно, і обережно змінюйте sync. «sync=disabled» — це не налаштування;
це маніпуляція контрактом із фізикою.
Завдання 5: Проінспектувати поведінку ARC (Linux)
cr0x@server:~$ awk 'NR==1 || /^(size|c |c_min|c_max|hits|misses|mfu_hits|mru_hits|prefetch_data_hits|prefetch_data_misses)/' /proc/spl/kstat/zfs/arcstats
13 1 0x01 204 33728 11970458852 6427389332172
size 4.20G
c 6.00G
c_min 1.00G
c_max 24.0G
hits 132948210
misses 21928411
mfu_hits 90128210
mru_hits 42820000
prefetch_data_hits 1428000
prefetch_data_misses 6180000
Що це означає: size — поточний розмір ARC, c — цільовий розмір, а лічильники hits/misses
підказують, чи читання дружнє до кешу. Prefetch misses можуть вказувати, що навантаження обходить послідовні евристики.
Рішення: Якщо miss переважають і ваше навантаження читаюче, вам може знадобитися більше RAM, краща локальність
або інша компоновка (дзеркала, спеціальний vdev для метаданих). Якщо ARC величезний і додатки своплять — лімітуйте ARC.
Завдання 6: Перевірити брудні дані ZFS і тиск TXG (Linux)
cr0x@server:~$ awk '/(dirty data|max dirty data|dirty data sync)/{print}' /proc/spl/kstat/zfs/arcstats
dirty data 812345678
max dirty data 4294967296
dirty data sync 0
Що це означає: Брудні дані — це записи, що очікують на скидання. Якщо брудні дані наближаються до max і залишаються там,
пул не встигає їх скинути. Ось коли TXG sync починає обмежувати записувачів.
Рішення: Якщо брудні дані хронічно високі, ви переганяєте пул. Зменшіть швидкість запису,
покращіть латентність запису vdev (більше vdev, швидші пристрої) або налаштуйте навантаження (більші послідовні записи, стиснення).
Завдання 7: Виявити біль синхронних записів і чи є SLOG
cr0x@server:~$ zpool status tank
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
ata-A ONLINE 0 0 0
ata-B ONLINE 0 0 0
logs
nvme-SLOG ONLINE 0 0 0
Що це означає: Розділ logs означає, що у вас є окремий лог‑пристрій. Без нього синхронні записи потрапляють на основні vdev і наслідують їхню латентність.
Рішення: Якщо у вас sync‑важке навантаження (бази даних, NFS з sync, зберігання VM),
розгляньте належний SLOG із захистом від втрати живлення. Якщо він вже є, а sync все ще повільний — перевірте, чи він не є вузьким місцем.
Завдання 8: Подивитися використання простору по датасетах і тиск снапшотів
cr0x@server:~$ zfs list -o name,used,avail,refer,compressratio -r tank
NAME USED AVAIL REFER RATIO
tank 1.20T 2.40T 128K 1.45x
tank/app 620G 2.40T 410G 1.62x
tank/app@daily-1 80G - 390G 1.60x
tank/logs 110G 2.40T 110G 1.05x
Що це означає: Снапшоти займають місце через змінені блоки. Якщо used зростає, а refer стабільний,
снапшоти (або клоні) тримають історію.
Рішення: Якщо пул заповнюється і продуктивність погіршується, перегляньте політику збереження снапшотів.
Залишайте ті, що потрібні, видаляйте непотрібні і припиніть вдавати, що «безкінечне збереження» безкоштовне.
Завдання 9: Перевірити фрагментацію пулу і запас ємності
cr0x@server:~$ zpool list -o name,size,alloc,free,frag,cap,dedup,health
NAME SIZE ALLOC FREE FRAG CAP DEDUP HEALTH
tank 3.60T 1.20T 2.40T 18% 33% 1.00x ONLINE
Що це означає: frag — евристика, але корисна напрямково. cap показує заповненість.
Коли cap піднімається понад ~70–80% на навантажених пулах, алокації ускладнюються і латентність зазвичай зростає.
Рішення: Якщо ви вище ~80% і латентність важлива — плануйте розширення ємності або міграцію зараз.
«Почекаємо до 95%» — це як опинитися в дебагу metaslab під вогнем.
Завдання 10: Перевірити ashift і розташування vdev (і зловити незворотні помилки рано)
cr0x@server:~$ zdb -C tank | egrep 'vdev|ashift|path' | head -n 20
vdev_tree:
type: 'root'
id: 0
guid: 1234567890123456789
children[1]:
type: 'mirror'
id: 0
ashift: 12
children[2]:
type: 'disk'
path: '/dev/disk/by-id/ata-A'
type: 'disk'
path: '/dev/disk/by-id/ata-B'
Що це означає: ashift: 12 означає 4K сектори. Якщо у вас 4K/8K‑нативні диски, а ashift занадто малий,
ви примусили поведінку read‑modify‑write, яка переслідуватиме вас.
Рішення: Якщо ashift неправильний — плануйте перебудову/міграцію. Немає магічної кнопки «змінити ashift на місці».
Завдання 11: Переконатися, що стиснення допомагає (а не просто ввімкнене)
cr0x@server:~$ zfs get -o name,property,value,source compression,compressratio tank/app
NAME PROPERTY VALUE SOURCE
tank/app compression zstd local
tank/app compressratio 1.62x -
Що це означає: Співвідношення показує реальну економію. Співвідношення близьке до 1.00x означає, що ваші дані нестисні або вже стиснені (медіа, зашифровані бінарні дані).
Рішення: Якщо співвідношення ~1.00x і CPU завантажений, розгляньте легше стиснення або його відключення.
Якщо співвідношення гарне — стиснення, ймовірно, дає вам запас по IO.
Завдання 12: Виявити scrub/resilver, що краде ваш IO‑бюджет
cr0x@server:~$ zpool status -x
pool 'tank' is healthy
cr0x@server:~$ zpool status tank | sed -n '1,12p'
pool: tank
state: ONLINE
scan: scrub in progress since Thu Dec 25 03:00:12 2025
540G scanned at 610M/s, 120G issued at 140M/s, 1.20T total
0B repaired, 9.77% done, 0:02:13 to go
Що це означає: Запущений scrub конкурує за читання (а іноді й за записи під час ремонтів).
Показник «issued» корисніший; він відображає те, що реально штовхають на пристрої.
Рішення: Якщо ви в інциденті продуктивності, можна призупинити або провести scrub у непік (залежить від можливостей платформи).
Але не «вирішуйте» продуктивність тим, що ніколи не робитимете scrub.
Завдання 13: Підтвердити mountpoint і уникнути випадкових подвійних монтувань
cr0x@server:~$ zfs get -o name,property,value mountpoint,canmount tank/app
NAME PROPERTY VALUE
tank/app mountpoint /srv/app
tank/app canmount on
Що це означає: Неправильно змонтовані датасети створюють інцидент, коли ви записуєте дані не туди, а потім «відновлюєте» зі снапшоту, який цього не зловив.
Рішення: Стандартизуйте mountpoint і застосовуйте це в провізіонуванні. Тимчасові монтування ставте під change‑менеджмент.
Завдання 14: Моніторити реальний IO по ZFS і знайти «тулуба» процесу
cr0x@server:~$ zpool iostat -w -v tank 1
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 1.20T 2.40T 110 2200 12.1M 280M
mirror-0 1.20T 2.40T 110 2200 12.1M 280M
ata-A - - 55 1100 6.0M 140M
ata-B - - 55 1100 6.1M 140M
-------------------------- ----- ----- ----- ----- ----- -----
Що це означає: Режим -w додає статистику латентності на деяких платформах/збірках; навіть без нього
видно шторм записів. Поєднайте з інструментами на рівні процесів (pidstat, iotop), щоб знайти джерело.
Рішення: Якщо одна задача заливає записами і штовхає TXG sync, обмежте її швидкість, ізолюйте в окремий датасет
або пересуньте на інший клас пулу. Спільні пули заохочують «булі» і карають усіх інших.
Жарт №2: L2ARC — це як корпоративний «Center of Excellence» — на папері чудово, дорого на зустрічах, і він не виправить вашу організаційну схему.
Швидкий план діагностики (перше/друге/третє)
Перше: визначити, чи це питання здоров’я, ємності чи конкуренції за ресурси
- Здоров’я:
zpool status -v. Є помилки, деградація, resilver або scrub? Виправляйте стан перед налаштуванням. - Запас ємності:
zpool list. Якщо ви понад ~80% на навантаженому пулі, припускайте, що алокації ускладнюються. - Це справді сховище?
iostat -xдля латентності пристроїв і їх завантаження. Високі await/queue = конкуренція за сховище.
Друге: визначити, чи болять читання, чи записи
- Мікс на рівні пулу:
zpool iostat -v 1показує операції читання/запису і пропускну здатність. - Підозра на синхронні записи: якщо додатки блокуються на commits/fsync, перевірте наявність SLOG і властивості датасету
sync/logbias. - Кут кешу: ARC‑статистика для hits/misses; якщо читання промахуються ARC і потрапляють на повільні диски — латентність слідує.
Третє: перевірити, чи відповідатиме компоновка робочому навантаженню
- Тип vdev: дзеркала для низької латентності випадкового IO; RAID‑Z для ємності і послідовних навантажень. Якщо ви обрали RAID‑Z для ферми VM з випадковими записами — пул робить саме те, що ви попросили.
- Розміри блоків: перевірте
recordsizeі (для zvol)volblocksize. Невідповідність створює write‑ампліфікацію і тиск TXG. - Спеціальний vdev: якщо метадані «гарячі» і у вас повільні диски, спеціальний vdev може допомогти — але тільки якщо ви розумієте наслідки щодо надлишковості.
Поширені помилки: симптоми → корінь → виправлення
1) «Все повільно, коли пул досягає ~85%»
Симптоми: зростаюча латентність запису, непередбачувані паузи, scrub/resilver триває вічно, операції з метаданими повільні.
Корінь: фрагментація metaslab + обмежені варіанти алокації при високому заповненні; copy-on-write це погіршує.
Виправлення: підтримуйте запас ємності (розширення раніше), зменшуйте churn (дисципліна збереження снапшотів), розгляньте додавання vdev для паралелізму. Не прагніть 95% заповнення на пулі критичному до продуктивності.
2) «Коміти бази даних займають 20–80 ms, але пропускна здатність начебто нормальна»
Симптоми: висока p99 латентність, потоки блокуються в fsync, TPS падає під час сплесків.
Корінь: вузьке місце шляху синхронних записів: немає SLOG, SLOG повільний або основний vdev повільний; лог‑записи серіалізуються.
Виправлення: використовуйте належний SLOG з захистом від втрати живлення для sync‑важких навантажень; перевірте властивості датасету sync і logbias; переконайтеся, що латентність vdev не патологічна.
3) «Ми додали L2ARC і стало гірше»
Симптоми: підвищений тиск на пам’ять, іноді зупинки, відсутність покращення hit rate.
Корінь: накладні витрати на індексацію L2ARC + кешування неправильної робочої множини; недостатньо RAM, тож ARC вже голодний.
Виправлення: спочатку додайте RAM, налаштуйте локальність навантаження, виміряйте ARC hit rate до/після. Використовуйте L2ARC, коли робоча множина більша за RAM, але ще піддається кешуванню і читаюча.
4) «Випадкові записи жахливі на нашому новому RAID‑Z пулі»
Симптоми: IOPS значно нижчі від очікуваного, висока латентність при низькій пропускній здатності, CPU виглядає не задіяним.
Корінь: витрати парності RAID‑Z і write‑ампліфікація на малих випадкових записах; TXG sync стає вузьким місцем.
Виправлення: використовуйте дзеркальні vdev для випадкових записів; або ізолюйте навантаження, налаштуйте recordsize/volblocksize і переконайтеся, що ви не змушуєте синхронні записи без потреби.
5) «Ми відключили sync, щоб “виправити” латентність і потім втратили дані»
Симптоми: продуктивність покращилася; після краху не вистачає або пошкоджені недавні транзакції на рівні додатку.
Корінь: ви змінили семантику довговічності. ZFS виконала ваші накази і підтвердила запис, перш ніж він став стійким.
Виправлення: поверніть sync до standard; використовуйте SLOG і належне обладнання; виправте реальне вузьке місце латентності замість підміни контракту.
6) «Scrub вбиває продуктивність кожного тижня»
Симптоми: передбачувані сплески латентності у вікні scrub, тайм‑аути у IO‑важких сервісах.
Корінь: scrub конкурує за IO з чутливими до латентності навантаженнями; відсутня дисципліна тротлінгу/планування.
Виправлення: плануйте scrub у непік, налаштовуйте поведінку scrub, доступну на вашій платформі, і ізолюйте навантаження між пулами/класами vdev за потреби.
Три корпоративні історії (анонімізовано, болісно реальні)
Інцидент через неправильне припущення: «Пул — це просто пул»
Середня компанія мігрувала флот хостів VM на новий пристрій зберігання на ZFS. Закупівля оптимізувала корисну ємність,
тож дизайн був «декілька широких RAID‑Z2 vdev із багатьма дисками». На папері — чудово.
На практиці: там зберігалося сотні дисків VM з малими випадковими операціями і періодичними sync‑сплесками.
Припущення, що спричинило інцидент, було просте: «більше дисків означає більше IOPS». Це правда, коли додаєш vdev,
а не коли додаєш диски всередину одного RAID‑Z vdev і очікуєш поведінки дзеркала. Під час першого великого патч‑вікна пул зазнав стійкого записного тиску, TXG почали синхронізуватися без зупинок, і латентність I/O у гостей зросла від «добре» до «вигортайте інцидент‑команду».
Дашборди не брешуть. Агрегована пропускна здатність була високою. Це робило все ще більш заплутаним: пропускна здатність здавалась нормальною,
але VM вмирали. Відсутнім метриком була хвостова латентність синхронних записів. Робочі навантаження не були обмежені по пропускній здатності;
вони були залежні від латентності підтвердження. Кожен fsync чекав за парністю і чергами vdev.
Виправлення не було «налаштуванням». Це була архітектура. Вони додали виділений дзеркальний пул для чутливого до латентності зберігання VM
і залишили RAID‑Z для бекапів і послідовних даних. Також переглянули значення датасетів: менші блоки там, де потрібно, і ніхто більше не чіпав sync=disabled без письмового прийняття ризику.
Оптимізація, що відгукнулась боком: special vdev як магічна кнопка швидкості
Інша організація мала великий пул на HDD‑дзеркалах, що обслуговував мільйони малих файлів. Метадані були «гарячі».
Хтось прочитав про special vdevs і запропонував: «Покладемо метадані на SSD і все прискориться». Це правда, але з застереженнями.
Застереження не обговорювали. Вони додали special vdev з меншою надлишковістю, ніж у головного пулу, бо «це ж просто метадані».
Це спрацювало відразу. Переліки директорій прискорилися, навантаження, що часто викликає stat, заспокоїлося, і команда оголосила перемогу.
Через місяць спеціальний пристрій почав кидати періодичні помилки. ZFS відреагував правильно: цілісність метаданих — не опція. Якщо ви втрачаєте special vdev і він недостатньо надлишковий, ви втрачаєте не просто продуктивність — ви можете втратити пул.
Інцидент не перетворився на заголовок про втрату даних, бо пристрій не помер повністю. Але вони отримали операційний шок, дорогий по часу: аварійне вікно, ескалація до вендора і напружена розмова про те, «чому ми поклали критичні дані пулу на єдину точку відмови?»
Провалена оптимізація не в тому, що special vdev погані. Провалена оптимізація в тому, що тритували функцію продуктивності як кеш. Special vdevs можуть зберігати метадані і малі блоки. Це робить їх структурними. Структурне означає, що надлишковість має відповідати очікуванням пулу. Вони перебудували special vdev як дзеркало, задокументували домен відмов і тільки потім широко впровадили.
Нудна, але правильна практика, що врятувала ситуацію: регулярні scrubs + дисципліна замін
Команда SaaS працювала з ZFS на звичайних серверах. Нічого гламурного: дзеркальні vdev, консервативний запас,
та розклад, що регулярно запускає scrub. Вони також мали звичку, яка здається нав’язливою, поки не рятує: якщо диск показує зростаючі лічильники помилок — його замінюють до «повного» відмови.
Одного тижня scrub повідомив про відремонтовані байти в пулі, який інакше виглядав здоровим. Ніхто з додатків не скаржився.
Ніхто не помічав. Ось суть: латентні помилки секторів не надсилають календарні нагадування.
Scrub знайшов невідповідності контрольних сум, прочитав з дзеркала, відремонтував і задокументував.
Команда розглядала відремонтовані байти як раннє попередження про апаратний дефект. Вони перевірили тренди помилок на рівні ОС,
замінили диск у заплановане вікно і resilvered, поки пул був здоровий і не під тиском. Заміна була нудною. Інцидент, який не стався, був би вже «захопливим».
Через місяць інший диск в іншому сервері помер жорстко під час піку. Той пул залишився онлайн, бо дзеркала й проактивна практика означали, що вони ніколи не працювали близько до краю. Ніхто поза командою не помітив.
Ось як виглядає робота з надійності: успіх, який неможливо показати в скриншоті.
Чек‑листи / покроковий план
Покроково: спроєктувати пул, який не соромитиме вас пізніше
- Класифікуйте робочі навантаження: випадкове читання, випадкове записування, послідовне, sync‑важке, метадані‑важке. Не усереднюйте їх у незрозумілу суміш.
- Виберіть тип vdev під навантаження: дзеркала для низької латентності; RAID‑Z для ємності і послідовної пропускної здатності. Змішані навантаження заслуговують на розділення через датасети або окремі пули.
- Плануйте кількість vdev для IOPS: потрібно більше IOPS? додавайте vdev, а не диски всередину одного RAID‑Z vdev.
- Вирішіть питання SLOG: лише якщо у вас є значущі синхронні записи. Оберіть пристрої з захистом від втрати живлення; дзеркальте SLOG, якщо ваша модель ризику того вимагає.
- Вирішіть питання special vdev: лише якщо метадані/малі блоки — вузьке місце. Узгодьте надлишковість зі значущістю пулу.
- Встановіть ashift правильно під час створення. Розглядайте його як незворотний вибір в практичних термінах.
- Встановіть дефолти датасетів:
compression=zstd(часто),atime=off(звично), recordsize під навантаження, і quotas/reservations, де потрібно. - Політика запасу ємності: визначте жорсткий поріг (наприклад 75–80%), за яким потрібно розширювати або мігрувати.
- Операційний ритм: регулярні scrubs, алерти на помилки, документовані процедури заміни.
Покроково: коли успадкували пул і не довіряєте йому
- Запустіть
zpool status -vі зафіксуйте початкові лічильники помилок і стан scrub. - Запустіть
zpool listі помітьте ємність і фрагментацію. - Запустіть
zpool iostat -v 1 10під нормальним навантаженням, щоб зрозуміти «норму». Збережіть вивід. - Аудит властивостей датасетів:
zfs get -rдляrecordsize,sync,compression,atime, quotas/reservations. - Інвентаризація спеціальних пристроїв: SLOG, L2ARC, special vdev. Підтвердьте надлишковість і стан.
- Перевірте ashift через
zdb -C. Якщо неправильний — зафіксуйте технічний борг з планом. - Перегляньте політику збереження снапшотів і шаблони росту. Видаляйте відповідально, але не дозволяйте снапшотам непомітно поглинати пул.
- Реалізуйте алерти: зміни стану пулу, дельти лічильників помилок, поріг ємності, збої scrub і незвична латентність.
Питання та відповіді
1) Чи є VDEV фактично RAID‑групою?
Функціонально — так: дзеркальний vdev нагадує RAID1, RAID‑Z нагадує парний RAID. Операційна відмінність у тому, що:
vdev — це одиниця, по якій ZFS робить стріпінг. Додавайте vdev, щоб отримати більше IOPS/паралелізму.
2) Чому продуктивність ZFS падає, коли пул заповнений?
Бо алокації стають обмеженими і фрагментованими. SPA має менше «хороших» варіантів, метадані ростуть, і записи перетворюються
на більш розкидані IO. Майже повні пули — дорогі пули.
3) Що конкретно означає TXG syncing для моїх додатків?
TXG syncing — це коли ZFS скидає брудні дані на диск. Якщо пул не встигає, ZFS обмежує записувачів, і ваш додаток це відчуває як латентність.
Sync‑важкі додатки відчують це сильніше, бо вони вимагають стійких підтверджень.
4) Чи замінює ARC Linux page cache?
Не зовсім. ZFS використовує ARC для керованого кешування. Ядро все ще має власні механізми page cache, але ZFS не типова файлова система
у способі керування кешованими блоками. Практична проблема — конкуренція за пам’ять: переконайтеся, що додатки теж мають достатньо RAM.
5) Коли варто додавати SLOG?
Коли ваші навантаження генерують значну кількість синхронних записів (бази даних, NFS з sync, зберігання VM, що робить flush),
і латентність має значення. Якщо навантаження — це переважно асинхронні стрімінгові записи, SLOG не допоможе.
6) Чи варто використовувати L2ARC?
Іноді. Якщо ваша робоча множина більша за RAM, читаюча і кешована, L2ARC може допомогти. Якщо ви write‑heavy, RAM‑голодні
або ваша робоча множина випадкова з малою повторюваністю, часто це нічого не дає або погіршує ситуацію.
7) У чому різниця між recordsize і volblocksize?
recordsize застосовується до файлів у датасетах і може змінюватись. volblocksize застосовується до zvol і фіксується при створенні.
Обирайте розміри блоків, що відповідають реальному IO вашого додатку.
8) Чи можна змінити рівень RAID‑Z або видалити vdev пізніше?
Припускайте «ні» при плануванні продакшну. Деякі розширення доступні в деяких реалізаціях, але видалення vdev і зміни RAID‑рівня — це не те, на що варто ставити бізнес.
Проєктуйте так, ніби ви житимете з рішенням.
9) Чи шкодить scrub SSD або сильно скорочує термін служби?
Scrub читає весь пул і може спричинити записи під час ремонтів. Це зношування, так — але альтернатива — не знати про латентну корупцію, поки вона не стане проблемою.
Частота scrub — це рішення ризику, а не забобон.
10) Чи варто вмикати dedup?
Тільки якщо у вас доведене dedup‑дружнє навантаження і достатньо пам’яті/CPU для його підтримки. У більшості загальних середовищ dedup — це податок на продуктивність і складність, що не окуповується.
Висновок: наступні кроки, які ви можете зробити цього тижня
ZFS не «складна». Вона чесна. Вона показує реальність того, що зберігання — це координована система: геометрія vdev,
таймінг TXG, поведінка ARC і політика алокації SPA — все це рано чи пізно з’явиться на ваших графіках латентності.
Практичні наступні кроки:
- Запустіть базові команди:
zpool status -v,zpool list,zpool iostat -v, і збережіть виводи як ваш «відомий добрий» стан. - Перевірте властивості датасетів для трьох найважливіших робочих навантажень; виправте очевидні невідповідності (recordsize, atime, compression).
- Встановіть політику запасу ємності і застосуйте оповіщення.
- Якщо у вас sync‑важкі навантаження — перевірте історію SLOG: або у вас є добрий SLOG, або ви приймаєте латентність.
- Заплануйте scrubs, моніторьте ремонти і замінюйте підозрілі диски раніше. Нудне — це мета.
Якщо запам’ятаєте одну річ: пул не є одиницею продуктивності. Віртуальний пристрій (vdev) — так. І TXG завжди тикатимуть у фоні,
готові «заплатити» за ті припущення, які ви зробили під час проєктування.