Моніторинг затримок ZFS: графіки, що виявляють катастрофу на ранній стадії

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

Збої сховища рідко починаються як «усе впало». Вони починаються з повідомлення в 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: Побудуйте дашборд затримок, який реально працює операційно

  1. Per-vdev read/write latency (p50/p95/p99, якщо можливо).
  2. Per-vdev utilization і глибина черги (або найближчий доступний проксі).
  3. Затримка синхронних записів і sync IOPS.
  4. TXG flush pressure: брудні дані, час txg sync, індикатори write throttling.
  5. ARC розмір, ціль, rate промахів, швидкість витіснення (не лише hit ratio).
  6. Місткість пулу і фрагментація.
  7. Стан scrub/resilver з анотаціями.
  8. Лічильники помилок: checksum, read/write помилки, I/O таймаути, скиди лінків.

Правило: Кожен граф має відповідати на питання, яке ви поставите о 3-й ночі. Якщо ні — видаліть його.

Чеклист B: Кроки реагування на інцидент (15 хвилин до ясності)

  1. Запустіть zpool status -v і підтвердіть стан, помилки, активність scrub/resilver.
  2. Запустіть zpool iostat -v 1 і знайдіть найгірший vdev/пристрій.
  3. Запустіть iostat -x 1 щоб підтвердити насичення пристрою або стрибки await.
  4. Перевірте zpool events -v і dmesg на скиди/таймаути/помилки.
  5. Перевірте властивості датасетів, що впливають на затримку (sync, logbias, recordsize, compression).
  6. Вирішіть: апаратна помилка, зсув навантаження, чи тиск через місткість/фрагментацію.
  7. Мітигайте: перемістіть навантаження, призупиніть scrub, зменшіть sync-тиск або замініть пристрій.

Чеклист C: Профілактична гігієна, що окупає витрати

  1. Оповіщайте про пороги місткості пулу і тренди фрагментації.
  2. Регулярно виконувати scrubs, але плануйте їх і контролюйте вплив.
  3. Відстежуйте лічильники помилок по пристроях і замінюйте зарано.
  4. Тримайте достатньо вільного простору для ефективної алокації ZFS.
  5. Підтверджуйте зміни невеликим бенчмарком і порівнянням хвостової латентності, а не лише середніми.

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 і лічильники помилок. Повільний диск часто стає неконсистентним, перш ніж стати мертвим.

Наступні кроки, які ви можете зробити цього тижня

  1. Додайте панелі per-vdev latency (читання/запис, перцентилі якщо можливо). Якщо не можете — принаймні відокремте метрики vdev/device від метрик пулу.
  2. Позначайте scrubs, resilvers і деплойти на тій же часовій шкалі, що й затримка. Вгадування дороге.
  3. Напишіть односторінковий runbook, використавши «Швидкий план діагностики» вище, і включіть точні команди, які ваша команда виконуватиме.
  4. Встановіть оповіщення про місткість, що спрацьовують до паніки: почніть попереджати на 70–75%, піднімайте оповіщення там, де ваше навантаження може терпіти.
  5. Запустіть один fio-тест (обережно, на безпечному датасеті) і зафіксуйте p95/p99. Це стане базовою «нормою».
  6. Попрактикуйте drill з заміни: визначте диск, симулюйте відмову в процесі (не фізично), підтвердьте, що вмієте інтерпретувати zpool status і діяти без імпровізації.

Мета не в побудові ідеального собору спостережуваності. Мета — побачити наступну катастрофу, поки вона ще маленька і на неї можна наступити.

← Попередня
PostgreSQL vs Redis: як зупинити шторм запитів по кешу, щоб база даних не «згоріла»
Наступна →
Пропуск RAID‑контролера для ZFS: IT‑режим проти HBA проти «фейкового HBA»

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