Збої сховища рідко починаються як «усе впало». Вони починаються з повідомлення в Slack: «чому додаток… пригальмовує?» Потім у вашої бази даних контрольні точки виконуються довше, черги зростають, і раптом ваші SLO нагадують гірськолижний схил.
ZFS відмінно зберігає цілісність даних. Водночас він добре приховує ранні сигнали всередині кількох лічильників, які ви навіть не графітуєте. Це про ті лічильники: графіки, які кажуть «щось не так», поки у вас ще є час виправити це без бойової кімнати.
Що означає «затримка» в ZFS (і чому це важливо для вашого додатку)
Більшість команд графікують пропускну здатність, бо це приємно: великі числа, яскраві панелі, що подобається керівництву. Затримка — це число, яке насправді болить користувачам. Один повільний I/O може призупинити транзакцію, блокувати робочий потік і перетворитися на чергу, яку розв’язувати доводиться хвилинами.
ZFS додає свої шари. Це не критика; це реальність copy-on-write, контрольних сум, стиснення та transaction groups. Ваш I/O не просто «прибивається до диска». Він проходить через:
- шлях додатку та файлової системи (syscalls, VFS)
- ZFS intent/logging для синхронної семантики (ZIL/SLOG)
- ARC (кеш в ОЗП) та опціональний L2ARC (флеш-кеш)
- DMU / metaslab allocation (куди записуються блоки)
- черги vdev (місце, де «виглядає нормально» перетворюється на «чому всі чекають»)
- фізичні пристрої (включно з їхнім поведінкою мікропрограм)
Коли хтось каже «ZFS повільний», перекладайте це. Питайте: повільні читання чи повільні записи? синхронні чи асинхронні? дрібні випадкові I/O чи великі послідовні? гарячий набір вміщується в ARC чи ні? Саме так ви обираєте правильні графіки та правильне виправлення.
Ще один практичний момент: середня затримка — брехун. Вам потрібні перцентилі (p95, p99) і контекст глибини черги. Система може мати «низьку середню затримку», а p99 палити ваш додаток живцем.
Жарт №1: Середня затримка — як середня температура: відмінно, поки не зрозумієш, що голова в духовці, а ноги в морозилці.
Цікавинки та історія (корисний формат)
- ZFS народився в Sun Microsystems з метою, що цілісність даних важливіша за все інше, тому контрольні суми та copy-on-write — незмінні функції.
- «ZIL» існує навіть без SLOG: ZIL — це лог у пулі, а SLOG — окремий пристрій, що може зберігати записи ZIL для прискорення синхронних записів.
- TXG (transaction groups) — це серцебиття: ZFS пакетно обробляє зміни і періодично їх скидає. Коли скидання стають повільними, затримка поводиться дивно — а потім катастрофічно.
- ARC — не «просто кеш»: ARC взаємодіє з тиском пам’яті, метаданими та prefetch; він може несподівано змістити навантаження з дисків у ОЗП.
- L2ARC був ризикованішим раніше: старі реалізації могли споживати багато ОЗП для метаданих, і прогрів поведе себе непередбачувано. Сучасні системи покращилися, але це все ще не безкоштовно.
- Стиснення може зменшувати затримку, коли воно перетворює випадкові читання на меншу кількість пристроїв IO — поки CPU не стане вузьким місцем або recordsize не розбіжиться з шаблоном доступу.
- RAIDZ змінює історію запису: дрібні випадкові записи на RAIDZ можуть спричинити read-modify-write накладні витрати, що проявляється як більша затримка та чергування на пристроях.
- Scrub обов’язкові операційно, але вони конкурують за IO. Якщо ви не керуєте впливом scrub, ваші користувачі зроблять це за вас через гнівні тікети.
- Спеціальні vdev змінили економіку метаданих: розміщення метаданих (і за потреби дрібних блоків) на швидких SSD може драматично покращити затримку для навантажень, важких на метадані.
Цитата, бо вона виживає в кожному інциденті зі сховищем: «Надія — не стратегія.»
— James Cameron
Графіки, що виявляють катастрофу на ранній стадії
Моніторинг затримки — це не один графік. Це невеликий набір графіків, що розповідають узгоджену історію. Якщо ваш інструмент моніторингу підтримує лише кілька панелей, оберіть наведені нижче. Якщо можете зробити більше — зробіть. Ви купуєте час.
1) Затримка пулу і vdev (читання/запис) з перцентилями
Потрібні затримки читання та запису по vdev, а не лише середнє по пулу. Пули ховають вбивство. Один деградований пристрій, один повільний SSD, один збій HBA — і пул виглядає «трохи гірше», тоді як один vdev палає.
Що це виявляє: один пристрій, що відмирає, GC прошивки, зупинки, голодування черги, проблема контролера на одній лінії.
Як це підводить: якщо ви графікуєте лише середні по пулу, пропустите стадію «одне погане яблуко» і виявите проблему на стадії «усе таймаутиться».
2) Сигнали глибини черги / часу очікування
Затримка без глибини черги — як дим без пожежної тривоги. У ZFS є внутрішні черги; диски мають черги; ОС має черги. Коли глибина черги зростає, затримка зростає, а пропускна здатність часто впирається в стелю. Це ранній підпис катастрофи.
Що це виявляє: насичення, троттлінг, раптові зміни навантаження, конкуренцію scrub/resilver, зміну властивостей датасету, що збільшує розмір IO або синхронну поведінку.
3) Затримка синхронних записів (ZIL/SLOG health)
Бази даних і NFS часто змушують синхронну семантику. Якщо ваш SLOG повільний або неправильно сконфігурований, користувачі вивчать нові слова. Графік:
- затримка синхронних записів (p95/p99)
- операцій синхронних записів за секунду
- затримка та використання пристрою SLOG
Що це виявляє: зношення SLOG, вимкнений кеш пристрою, невідповідні вимоги щодо захисту від втрати живлення, випадкове вилучення SLOG або «швидкий» споживчий SSD, що зупиняється під синхронним навантаженням.
4) Час коміту TXG і тиск «брудних» даних
Коли ZFS не встигає скинути брудні дані, усе накопичується. Моніторте:
- час синхронізації TXG (або проксії типу «time blocked in txg»)
- розмір брудних даних
- події write throttle
Що це виявляє: повільні диски, надміру навантажені пули, невідповідність recordsize, дивну поведінку SMR-дисків, RAIDZ-накладні витрати при випадкових записах.
5) ARC hit ratio з контекстом (і промахи, що важливі)
ARC hit ratio — класичний показник для краси. Високий hit ratio все одно може приховувати затримку, якщо промахи стаються на критичному шляху (промахи метаданих або випадкові читання, що давлять повільний vdev). Графік:
- розмір ARC та цільовий розмір
- ARC hit ratio
- метадані vs дані hits (якщо можливо)
- швидкість витіснення
Що це виявляє: тиск пам’яті, зміни щільності контейнерів, оновлення ядра, що змінює поведінку ARC, або нове навантаження, що викидає корисні дані з кешу.
6) Фрагментація і поведінка metaslab allocation (повільні катастрофи)
Фрагментація — не миттєвий біль; це біль у майбутньому. Коли вільного місця стає мало і фрагментація росте, алокація ускладнюється і IO стає більш випадковим. Графік:
- відсоток вільного простору пулу
- відсоток фрагментації
- середній розмір записаного блоку (якщо доступно)
Що це виявляє: міфи «нам нормально при 20% вільного», накопичення snapshot, та навантаження, що ламає дрібні блоки.
7) Накладання впливу scrub/resilver
Scrub та resilver необхідні. Вони також важкі для IO. Ваш моніторинг повинен маркувати час їх виконання. Інакше ви сприймете «очікуваний IO тиск» як «містичну деградацію продуктивності», або, ще гірше, відключите scrubs і порадієте покращенню.
8) Помилки, що передують стрибкам затримки
Графікуйте кількість:
- checksum помилок
- read/write помилок
- таймаутів та скидів лінку (з журналів ОС)
Інциденти затримки часто починаються з «нешкідливих» повторних спроб. Повторні спроби — не нешкідливі; це множення I/O з поганим характером.
Швидкий план діагностики (перші / другі / треті кроки)
Це послідовність «сирена дзвонить». Вона оптимізована для швидкості та правильності, а не для витонченості.
Перший: вирішіть, чи це затримка пристрою, чергування ZFS чи зміна навантаження
- Подивіться на vdev read/write latency. Чи один vdev зашкалює?
- Подивіться на IOPS vs throughput. Чи змінилось навантаження з послідовного на випадкове?
- Перевірте sync write rate. Чи щось переключилось у синхронну семантику?
Другий: підтвердіть, чи пул блокується TXG flush або sync записами
- Якщо sync latency висока і SLOG насичений: ви в зоні ZIL/SLOG.
- Якщо async writes повільні і брудних даних багато: ви в зоні TXG/flush.
- Якщо читання повільні при низьких ARC hits: у вас проблема робочого набору в кеші.
Третій: шукайте «нудні» корінні причини, що завжди перемагають
- Пристрій виходить з ладу (SMART, лічильники помилок, таймаути).
- Запущено scrub/resilver, що конкурує за ресурси.
- Пул занадто заповнений або занадто фрагментований.
- Недавні зміни: recordsize, compression, sync, logbias, special vdev, volblocksize, конфігурація бази даних.
Якщо ви не можете відповісти «який vdev повільний» за п’ять хвилин, ваш моніторинг не завершений. Виправте це перед наступним інцидентом, що виправить його за вас.
Практичні завдання: команди, виходи та рішення (12+)
Це виконувані завдання, які ви можете зробити на типовій Linux-системі з ZFS. Мета — не зазубрювати команди, а зв’язати вихід із рішенням. Копіюйте/вставляйте з наміром.
Завдання 1: Визначити пул і його топологію
cr0x@server:~$ sudo zpool status -v
pool: tank
state: ONLINE
scan: scrub repaired 0B in 02:11:34 with 0 errors on Sun Dec 22 03:10:12 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
logs
nvme2n1 ONLINE 0 0 0
errors: No known data errors
Що це означає: У вас RAIDZ2 для місткості, зеркальна швидка vdev (тут показано як mirror-1) і окремий log-пристрій.
Рішення: Коли затримка стрибне, перевіряйте кожен із цих компонентів окремо. Якщо синхронна затримка зростає, пристрій logs підозрілий у першу чергу.
Завдання 2: Стежити за затримкою по vdev і поведінкою черги в реальному часі
cr0x@server:~$ sudo zpool iostat -v tank 1
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 5.21T 9.33T 812 604 98.6M 41.2M
raidz2-0 5.01T 9.33T 740 520 92.1M 38.0M
sda - - 98 70 11.8M 5.2M
sdb - - 110 74 12.0M 5.4M
sdc - - 96 68 11.5M 5.1M
sdd - - 99 69 11.6M 5.1M
sde - - 112 75 12.1M 5.6M
sdf - - 225 164 33.1M 11.6M
mirror-1 210G 1.59T 72 84 6.5M 3.2M
nvme0n1 - - 36 42 3.2M 1.6M
nvme1n1 - - 36 42 3.3M 1.6M
logs - - - - - -
nvme2n1 - - 0 180 0 2.1M
-------------------------- ----- ----- ----- ----- ----- -----
Що це означає: Ви бачите розподіл. Один диск (sdf) виконує набагато більше роботи, що може бути нормою (ефект розміщення) або підозрілим (гарячі точки, помилки або повільні сусіди).
Рішення: Якщо один пристрій показує непропорційно велику роботу або зміни продуктивності під навантаженням, скорелюйте з журналом ядра і SMART для цього пристрою. Якщо сплески синхронних записів — перевірте лог-пристрій.
Завдання 3: Отримати затримку на рівні блочного шару (чи пристрої зависають?)
cr0x@server:~$ iostat -x 1 3
Linux 6.6.44 (server) 12/26/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
4.12 0.00 1.88 6.05 0.00 87.95
Device r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 8.2 6.0 1024.0 512.0 185.1 0.9 22.4 18.1 28.3 0.9 12.3
sdf 32.1 25.8 8192.0 2048.0 356.7 7.8 118.6 101.2 140.8 1.1 98.7
nvme2n1 0.0 220.0 0.0 2304.0 20.9 0.5 2.3 0.0 2.3 0.1 2.6
Що це означає: sdf насичений (%util близько 100) з високим await і великою чергою (avgqu-sz). Це ваша фабрика затримок.
Рішення: Ставтеся до цього як до ймовірно несправного пристрою, проблеми шляху або гарячої точки навантаження. Перейдіть від ZFS до доказів на рівні ОС і апаратури.
Завдання 4: Перевірити події здоров’я ZFS і недавні зміни
cr0x@server:~$ sudo zpool events -v | tail -n 20
TIME CLASS
Dec 26 2025 10:42:18.911482 ereport.fs.zfs.io
pool = tank
vdev = /dev/sdf
errno = 5
error = Input/output error
Dec 26 2025 10:42:19.002114 ereport.fs.zfs.checksum
pool = tank
vdev = /dev/sdf
errors = 3
Що це означає: ZFS записує IO та checksum проблеми для /dev/sdf. Сплески затримки і помилки ходять поруч.
Рішення: Почніть план заміни. Якщо бачите таймаути/скиди, перевірте кабелі/HBA. Не намагайтесь «натюнити» вихід із помираючого диска.
Завдання 5: Отримати SMART/NVMe статус (підтвердити апаратну історію)
cr0x@server:~$ sudo smartctl -a /dev/sdf | egrep -i 'Reallocated|Pending|Offline|CRC|Power_On|Temperature|error'
Power_On_Hours 0x0032 092 092 000 Old_age Always - 35621
Reallocated_Sector_Ct 0x0033 089 089 010 Pre-fail Always - 24
Current_Pending_Sector 0x0012 098 098 000 Old_age Always - 3
UDMA_CRC_Error_Count 0x003e 199 199 000 Old_age Always - 12
SMART Error Log Version: 1
ATA Error Count: 7
Що це означає: Перевиділені й очікувані сектори плюс CRC помилки. Диск і/або шлях поводяться ненормально. Це не «можливо».
Рішення: Замініть диск і перевірте кабель/бекаплейн/HBA на наявність CRC проблем. Якщо CRC зростає на кількох дисках — підозрюйте шлях, а не лише диск.
Завдання 6: Підтвердити, чи вузьке місце — синхронні записи (ZIL/SLOG)
cr0x@server:~$ sudo zfs get -o name,property,value -s local,default sync,logbias tank
NAME PROPERTY VALUE
tank logbias latency
tank sync standard
Що це означає: Ви не змушуєте sync завжди, але додатки, що викликають fsync() або O_DSYNC, все одно генеруватимуть sync записи. logbias=latency типово для баз даних/NFS.
Рішення: Якщо sync latency висока і у вас є SLOG, перевірте його стан і придатність. Якщо SLOG немає і ваше навантаження синхронно-важке — додайте його (правильно).
Завдання 7: Перевірити, чи існує SLOG і чи він дійсно використовується
cr0x@server:~$ sudo zpool status tank | sed -n '/logs/,$p'
logs
nvme2n1 ONLINE 0 0 0
Що це означає: Є log vdev. Це не доводить його працездатності; це доводить ваше намір.
Рішення: Якщо sync latency погана, навантажте nvme2n1 і подивіться на його затримки в навантаженні; підтвердіть наявність захисту від втрати живлення, потрібного для вашого ризик-профілю.
Завдання 8: Подивіться на поведінку ARC (допомагає кеш чи відбувається thrash?)
cr0x@server:~$ arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
10:55:01 812 96 11 38 4 58 7 8 33 128G 144G
10:55:02 790 210 27 120 15 82 10 8 10 128G 144G
10:55:03 805 240 30 150 19 82 10 8 9 128G 144G
Що це означає: Рівень промахів швидко зростає. Якщо це збігається зі стрибками затримки, ваш робочий набір міг вийти за межі ARC, або нове навантаження викидає корисні дані.
Рішення: Дослідіть, що змінилось (деплой, патерн запитів, нові орендарі). Розгляньте додавання ОЗП, оптимізацію патернів доступу або використання special vdev для метаданих, якщо домінують промахи метаданих.
Завдання 9: Перевірити заповненість пулу і фрагментацію (повільні бомби затримки)
cr0x@server:~$ sudo zpool list -o name,size,alloc,free,capacity,fragmentation,health
NAME SIZE ALLOC FREE CAPACITY FRAG HEALTH
tank 14.5T 13.2T 1.3T 91% 62% ONLINE
Що це означає: 91% заповнений та 62% фрагментації. ZFS може працювати так, але він не працюватиме радісно. Алокація ускладнюється, IO стає випадковим, затримка зростає.
Рішення: Звільніть місце. Додайте vdev (правильно), видаліть старі snapshot/дані або перемістіть дані. Не «налаштовуйте» навколо майже повного пулу; це заперечення з графіками.
Завдання 10: Визначити датасети з ризиковими властивостями для затримки
cr0x@server:~$ sudo zfs get -r -o name,property,value recordsize,compression,atime,sync,primarycache,secondarycache tank/app
NAME PROPERTY VALUE
tank/app recordsize 128K
tank/app compression lz4
tank/app atime off
tank/app sync standard
tank/app primarycache all
tank/app secondarycache all
tank/app/db recordsize 128K
tank/app/db compression lz4
tank/app/db atime off
tank/app/db sync standard
tank/app/db primarycache all
tank/app/db secondarycache all
Що це означає: Розумні значення за замовчуванням, але recordsize=128K може бути неправильним для деяких DB-патернів (особливо багато випадкових 8–16K I/O). Неправильний recordsize може підвищити read-modify-write і посилити затримку.
Рішення: Якщо ваше навантаження — випадкові дрібні блоки, розгляньте датасет, налаштований для цього навантаження (часто 16K) і перевірте реальним IO-тестом. Не змінюйте recordsize в польоті без плану: це впливає на нові записані блоки.
Завдання 11: З’ясувати, чи scrub/resilver відбирає у вас ресурси
cr0x@server:~$ sudo zpool status tank
pool: tank
state: ONLINE
scan: scrub in progress since Fri Dec 26 09:58:41 2025
3.12T scanned at 1.25G/s, 1.88T issued at 780M/s, 5.21T total
0B repaired, 36.15% done, 01:29:13 to go
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
errors: No known data errors
Що це означає: Scrub виконується. Навіть при здоровому стані scrubs підвищують затримку, споживаючи IO та слоти черги.
Рішення: Якщо це продакшн-інцидент, розгляньте паузу scrub під час піку і перенесення на інший час. Але не «вирішуйте затримку» відключенням scrub назавжди. Це шлях до прихованої корупції і поганого тижня.
Завдання 12: Перевірити тиск snapshot (вплив на простір і продуктивність)
cr0x@server:~$ sudo zfs list -t snapshot -o name,used,refer,creation -S used | head
NAME USED REFER CREATION
tank/app/db@hourly-2025-12-26-10 78G 1.2T Fri Dec 26 10:00 2025
tank/app/db@hourly-2025-12-26-09 74G 1.2T Fri Dec 26 09:00 2025
tank/app/db@hourly-2025-12-26-08 71G 1.2T Fri Dec 26 08:00 2025
tank/app/db@hourly-2025-12-26-07 69G 1.2T Fri Dec 26 07:00 2025
tank/app/db@hourly-2025-12-26-06 66G 1.2T Fri Dec 26 06:00 2025
tank/app/db@hourly-2025-12-26-05 64G 1.2T Fri Dec 26 05:00 2025
tank/app/db@hourly-2025-12-26-04 62G 1.2T Fri Dec 26 04:00 2025
tank/app/db@hourly-2025-12-26-03 61G 1.2T Fri Dec 26 03:00 2025
tank/app/db@hourly-2025-12-26-02 59G 1.2T Fri Dec 26 02:00 2025
Що це означає: Snapshots займають серйозний простір. Інтенсивне створення snapshot з великим churn підвищує фрагментацію і зменшує вільний простір, що погіршує затримку.
Рішення: Встановіть політику збереження, що відповідає бізнес-потребам, а не тривозі. Якщо вам потрібні часті snapshots — плануйте місткість і розміщення vdev під це.
Завдання 13: Перевірити, чи «тюнінг» дійсно допоміг (fio)
cr0x@server:~$ fio --name=randread --directory=/tank/app/test --rw=randread --bs=16k --iodepth=32 --numjobs=4 --size=4g --time_based --runtime=30 --group_reporting
randread: (groupid=0, jobs=4): err= 0: pid=21144: Fri Dec 26 10:58:22 2025
read: IOPS=42.1k, BW=658MiB/s (690MB/s)(19.3GiB/30001msec)
slat (nsec): min=500, max=220000, avg=1120.4, stdev=820.1
clat (usec): min=85, max=14200, avg=302.5, stdev=190.2
lat (usec): min=87, max=14203, avg=304.0, stdev=190.4
clat percentiles (usec):
| 1.00th=[ 120], 5.00th=[ 150], 10.00th=[ 170], 50.00th=[ 280],
| 90.00th=[ 470], 95.00th=[ 560], 99.00th=[ 900], 99.90th=[ 3100]
Що це означає: Ви маєте дані перцентилів. p99 ≈ 900us може бути прийнятним; p99.9 ≈ 3.1ms — причина для занепокоєння в деяких OLTP-сценаріях. Хвіст важливий.
Рішення: Порівняйте до/після змін тюнінгу. Якщо p99 погіршився, а середнє покращилось — ви не «оптимізували», ви просто перемістили біль у хвіст, де живуть інциденти.
Завдання 14: Перевірити помилки на рівні ядра та скиди
cr0x@server:~$ sudo dmesg -T | egrep -i 'reset|timeout|blk_update_request|I/O error|nvme|ata' | tail -n 20
[Fri Dec 26 10:42:16 2025] ata7.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 frozen
[Fri Dec 26 10:42:16 2025] ata7.00: failed command: READ DMA EXT
[Fri Dec 26 10:42:16 2025] blk_update_request: I/O error, dev sdf, sector 983742112 op 0x0:(READ) flags 0x0 phys_seg 8 prio class 0
[Fri Dec 26 10:42:17 2025] ata7: hard resetting link
[Fri Dec 26 10:42:18 2025] ata7: SATA link up 6.0 Gbps (SStatus 133 SControl 300)
Що це означає: ОС бачить скиди лінку та I/O помилки. Це узгоджується з попередніми подіями ZFS і зависанням в iostat.
Рішення: Замініть підозрілі апаратні компоненти та перевірте фізичний шлях. Також очікуйте, що стрибки затримки корелюватимуть з цими скидами; позначайте їх на графіках, якщо можете.
Жарт №2: Коли прошивка SSD починає виконувати garbage-collect під час інциденту, це як прибиральник, що пилососить під час протипожежної тренування — технічно працює, емоційно марно.
Три корпоративні міні-історії з передової
Міні-історія 1: Інцидент через хибне припущення
Середній SaaS запустив PostgreSQL на томах під ZFS. У них був нормальний хардвер, гідний моніторинг і впевнене припущення: «NVMe швидкий, отже синхронні записи не проблема». Вони графікували throughput і CPU і називали це спостережуваністю.
Потім запустили нову фічу: більше дрібних транзакцій, більше commit-ів, більше fsync-ів. За кілька годин p99 API-латентності подвоївся. База не впала. Вона просто почала рухатися, як людина по мокрому цементі. Інженери ганялися за планами запитів, пулами з’єднань, паузами GC—за чим завгодно, тільки не за сховищем, бо «сховище — NVMe».
Відсутній графік був sync write latency. Коли його додали, картина стала очевидною: чистий пилкоподібний патерн нормальної поведінки, перерваний страшними стрибками. Ці стрибки збігалися з активністю ZIL і зависаннями пристрою. Їх «швидкий» SLOG був споживчим NVMe без захисту від втрати живлення, і під тривалим sync-навантаженням він періодично зависав.
Вони замінили SLOG на enterprise-пристрій, що дає стабільну латентність, і перевели кілька критичних датасетів на sync=standard з явними налаштуваннями стійкості на рівні додатку, замість тотального примусу sync. Інцидент закінчився швидко — після довгого обходу всіх систем, крім винної.
Хибне припущення було не «NVMe швидke». Воно полягало в тому, що «швидкий означає стабільний». Моніторинг затримки покарає це переконання до того, як покарають клієнти.
Міні-історія 2: Оптимізація, що відкотилася
Команда внутрішньої платформи хотіла зменшити диск I/O. Вони помітили багато операцій з метаданими і вирішили «прискорити» додаванням L2ARC. Виділили великий SSD, увімкнули L2ARC і спостерігали збільшення кешу. Перемога, правда?
Через тиждень з’явилися періодичні стрибки затримки для сервісів з великою часткою читань. Графіки були заплутані: throughput стабільний, CPU помірний, ARC hit ratio виглядав нормально. Але хвостова латентність стала гіршою. Користувачі скаржилися на періодичні уповільнення, що не відображалися в середніх.
Провал був тонким: L2ARC був величезним, і його метадані споживали ОЗП не по-дрібниці. Під тиском пам’яті інші сервіси відбирали пам’ять; ARC стискався; частота витіснень зростала; і система коливалася між «теплим кешем» і «холодним кешем». Кожне коливання породжувало сплеск читань диска, чергування і хвостову латентність.
Вони виправили це, підібравши розмір L2ARC, захистивши запас ОЗП і змістивши фокус на special vdev для метаданих (що зменшило промахи на критичному шляху), замість намагання вирішити проблему робочого набору кешом. Оптимізація не була дурною — вона була неповною. Вона трактувала «більше кешу» як універсальне благо, а не як компроміс.
Міні-історія 3: Нудна практика, що врятувала день
Фінансова команда обслуговувала клієнтські API на ZFS. У них була культура цілком неприваблива: кожна зміна мала план відкату, у кожного пулу були тижневі вікна scrub, і на кожному дашборді було кілька панелей, про які ніхто не думав, поки вони не стали важливими.
Одна з таких панелей — пер-vdev latency з позначками для scrub та деплоїв. Інша — простий лічильник checksum помилок по пристроях. Це було нудно. Воно залишалося плоским. Люди забули про його існування.
У вівторок після обіду лічильник checksum помилок почав зростати на одному диску. Латентність ще не була поганою. Пропускна здатність виглядала нормально. Скарг від користувачів не було. Інженер on-call замінив диск того вечора, бо інструкція фактично казала: «не сперечайся з checksum помилками».
Два дні потому постачальник підтвердив проблему з партією того модельного ряду дисків. Інші команди виявили проблему під час resilver-ів і brownout-ів. Ця команда знайшла її у плоскому графіку, що трохи струснувся. Заощадження не були героїчними; вони були процедурними. Їхня «нудна» практика перетворила майбутній інцидент на завдання з технічного обслуговування.
Типові помилки: симптом → корінь проблеми → виправлення
1) Симптом: стрибки p99 write latency, але throughput виглядає нормально
Корінь проблеми: один пристрій стає нестабільним (GC прошивки, несправний диск, скиди лінку), тоді як середнє по пулу це ховає.
Виправлення: графікуйте per-vdev latency; підтвердіть через iostat -x і журнали ядра; замініть пристрій або виправте шлях. Не «налаштовуйте ZFS» спочатку.
2) Симптом: коміти бази даних повільні після «апгрейду сховища»
Корінь проблеми: SLOG відсутній, повільний або непридатний для потреб синхронної стійкості; або датасет випадково переключено в sync=always.
Виправлення: перевірте, чи пул має log vdev; оцініть sync write latency; переконайтеся, що SLOG призначений для стабільних низьких латентностей і має характеристики захисту від втрати живлення; відкотіть випадкові зміни властивостей.
3) Симптом: затримка погіршується під час бекапів/snapshots
Корінь проблеми: churn snapshot збільшує фрагментацію і зменшує вільний простір; бекап-читання конфліктують з продукційним IO.
Виправлення: плануйте бекапи й scrubs; використовуйте обмеження пропускної здатності, якщо доступні; поліпшіть політику зберігання; додайте місткість, щоб тримати пул комфортно нижче «панічного» рівня.
4) Симптом: читання повільні лише після деплою або додавання орендаря
Корінь проблеми: робочий набір більше не поміщається в ARC, або кількість промахів метаданих зросла; ARC thrash через тиск пам’яті.
Виправлення: додайте запас ОЗП; ідентифікуйте «шумних сусідів»; розгляньте special vdev для метаданих; не додавайте масивний L2ARC без планування ОЗП.
5) Симптом: «усе повільніше» коли виконується scrub
Корінь проблеми: scrub IO конкурує з продукцією; пул майже насичений; черги vdev заповнені.
Виправлення: запускати scrubs поза піковим часом; якщо платформа дозволяє — обмежити швидкість scrub; забезпечити достатню кількість шпинделів/IOPS для обох завдань. Якщо пул не може scrub без шкоди для користувачів — він недомірений.
6) Симптом: висока затримка при низькому використанні пристрою
Корінь проблеми: чергування вище блочного шару (внутрішні блокування ZFS, блокування TXG sync, насичення CPU, звільнення пам’яті), або IO синхронні та серіалізовані.
Виправлення: перевірте завантаження CPU і пам’яті; шукайте зростання часу TXG sync; перевірте sync-навантаження і SLOG; підтвердіть, що ваше навантаження не є випадково однопотоковим на рівні сховища.
7) Симптом: продуктивність погіршується протягом місяців без очевидного інциденту
Корінь проблеми: пул заповнюється, фрагментація зростає, накопичуються snapshots; алокація ускладнюється і IO-узори погіршуються.
Виправлення: планування місткості з оповіщеннями (тригери на 70/80/85%); політика збереження snapshot; додавання vdev до того, як пул стане генератором скарг.
Чеклисти / покроковий план
Чеклист A: Побудуйте дашборд затримок, який реально працює операційно
- Per-vdev read/write latency (p50/p95/p99, якщо можливо).
- Per-vdev utilization і глибина черги (або найближчий доступний проксі).
- Затримка синхронних записів і sync IOPS.
- TXG flush pressure: брудні дані, час txg sync, індикатори write throttling.
- ARC розмір, ціль, rate промахів, швидкість витіснення (не лише hit ratio).
- Місткість пулу і фрагментація.
- Стан scrub/resilver з анотаціями.
- Лічильники помилок: checksum, read/write помилки, I/O таймаути, скиди лінків.
Правило: Кожен граф має відповідати на питання, яке ви поставите о 3-й ночі. Якщо ні — видаліть його.
Чеклист B: Кроки реагування на інцидент (15 хвилин до ясності)
- Запустіть
zpool status -vі підтвердіть стан, помилки, активність scrub/resilver. - Запустіть
zpool iostat -v 1і знайдіть найгірший vdev/пристрій. - Запустіть
iostat -x 1щоб підтвердити насичення пристрою або стрибки await. - Перевірте
zpool events -vіdmesgна скиди/таймаути/помилки. - Перевірте властивості датасетів, що впливають на затримку (
sync,logbias,recordsize,compression). - Вирішіть: апаратна помилка, зсув навантаження, чи тиск через місткість/фрагментацію.
- Мітигайте: перемістіть навантаження, призупиніть scrub, зменшіть sync-тиск або замініть пристрій.
Чеклист C: Профілактична гігієна, що окупає витрати
- Оповіщайте про пороги місткості пулу і тренди фрагментації.
- Регулярно виконувати scrubs, але плануйте їх і контролюйте вплив.
- Відстежуйте лічильники помилок по пристроях і замінюйте зарано.
- Тримайте достатньо вільного простору для ефективної алокації ZFS.
- Підтверджуйте зміни невеликим бенчмарком і порівнянням хвостової латентності, а не лише середніми.
FAQ
1) Який один найважливіший граф затримки ZFS?
Per-vdev latency (читання та записи). Середні по пулу ховають ранню стадію, коли один пристрій псує всім день.
2) Чому потрібні перцентилі? Хіба середнього недостатньо?
Середні приховують поведінку хвоста. Користувачі відчувають p99. Бази даних відчувають p99. Ваш канал інцидентів по суті — це система повідомлення p99.
3) Чи додавання SLOG завжди зменшує затримку?
Ні. Воно зменшує затримку для синхронних записів, якщо SLOG має низьку й стабільну затримку запису. Поганий SLOG може зробити все гірше.
4) Як зрозуміти, чи моє навантаження синхронно-важке?
Виміряйте. Дивіться на високу частоту sync write ops і високу sync latency; корелюйте з latency комітів бази даних, поведінкою NFS sync або додатками, що викликають fsync().
5) Чи може пул бути «здоровим» і водночас мати жахливу затримку?
Абсолютно. «Health» — про коректність і доступність. Затримка — про продуктивність. Пул може бути ONLINE, в той час як один диск періодично зависає.
6) Чи справді настільки погано майже повний пул? У нас ще є вільне місце.
Так, це так погано. Вище ~80–85% заповнення (залежно від навантаження) алокація ускладнюється, фрагментація зростає, і хвостова латентність набуває зубів.
7) Чи варто вимкнути scrubs, щоб тримати низьку затримку?
Ні. Scrub дозволяють знайти приховану корупцію і проблеми дисків. Плануйте їх і керуйте впливом; не ігноруйте ентропію.
8) Стиснення допомагає чи шкодить затримці?
І те, й інше, залежно від навантаження. Стиснення може зменшити IO і покращити затримку, але додає навантаження на CPU і змінює розподіл розмірів IO. Міряйте на власних даних.
9) Чому бачу високу затримку при низькому %util на дисках?
Бо вузьке місце може бути вище диска: блокування TXG sync, звільнення пам’яті, насичення CPU або серіалізоване синхронне навантаження.
10) Який найшвидший спосіб спіймати диск, що вмирає, до його виходу з ладу?
Графікуйте per-device latency і лічильники помилок. Повільний диск часто стає неконсистентним, перш ніж стати мертвим.
Наступні кроки, які ви можете зробити цього тижня
- Додайте панелі per-vdev latency (читання/запис, перцентилі якщо можливо). Якщо не можете — принаймні відокремте метрики vdev/device від метрик пулу.
- Позначайте scrubs, resilvers і деплойти на тій же часовій шкалі, що й затримка. Вгадування дороге.
- Напишіть односторінковий runbook, використавши «Швидкий план діагностики» вище, і включіть точні команди, які ваша команда виконуватиме.
- Встановіть оповіщення про місткість, що спрацьовують до паніки: почніть попереджати на 70–75%, піднімайте оповіщення там, де ваше навантаження може терпіти.
- Запустіть один fio-тест (обережно, на безпечному датасеті) і зафіксуйте p95/p99. Це стане базовою «нормою».
- Попрактикуйте drill з заміни: визначте диск, симулюйте відмову в процесі (не фізично), підтвердьте, що вмієте інтерпретувати
zpool statusі діяти без імпровізації.
Мета не в побудові ідеального собору спостережуваності. Мета — побачити наступну катастрофу, поки вона ще маленька і на неї можна наступити.