Ваш хост Debian 13 «зависає», SSH‑сесії підвисають, графіки Prometheus схожі на електрокардіограму, CPU у top показує 2%… тільки iowait зафіксовано на 100%. Відчуття таке, ніби машина ввімкнена, але емоційно недоступна.
Це рідко є загадкою. Зазвичай це один шумний процес або VM, що робить щось «повністю логічне» у найневдаліший момент, плюс сховище, яке не встигає. Завдання — не медитувати над проблемою. Завдання — швидко назвати винного, вирішити: вбити, обмежити або полагодити, і повернути хост у робочий стан.
Ментальна модель: що насправді означає 100% iowait
iowait — це не «ваш диск на 100% зайнятий». Це означає «ваші CPU мають runnable‑завдання, але ці завдання заблоковані в очікуванні завершення I/O». Якщо ви бачите високий iowait при низькому використанні CPU, ядро робить вам послугу — не витрачає зайві цикли. Користувачі інтерпретують це як «сервер помер», бо з їхньої точки зору так і є.
На Debian 13 типовий сценарій такий:
- Якась робота починає виконувати багато I/O (записи — класичний тригер).
- Глибина черги на блочному пристрої різко зростає.
- Латентність вибухає (мілісекунди перетворюються на секунди).
- Потоки блокуються у стані D (uninterruptible sleep), і система відчувається «замороженою».
Що ви маєте відповісти за менш ніж 10 хвилин:
- Який пристрій? (nvme0n1? md0? dm-crypt? NFS‑монтування?)
- Який тип навантаження? (латентність? насичення? повторні спроби? flush/sync?)
- Яке джерело? (PID? контейнер? VM/гост?)
- Яка дія? (kill, throttle, перемістити, полагодити обладнання, змінити конфіг)
Суха правда: «iowait 100%» — це симптом, а не діагноз. Діагноз — це черга та джерело.
Цитата, яку варто тримати на стіні, бо вона — увесь сенс: «Hope is not a strategy.»
— Gene Kranz.
Жарт №1: iowait — це спосіб Linux сказати: «Я б з радістю допоміг, але чекаю, поки сховище дочитає свій довгий роман.»
Швидкий плейбук діагностики (10 хвилин)
Хвилина 0–1: підтвердьте, що це I/O, а не інший різновид проблеми
- Перевірте load, iowait і кількість заблокованих задач.
- Якщо ви бачите багато задач у стані D і load росте при низькому використанні CPU, ви в I/O‑світлі.
Хвилина 1–3: визначте пристрій, що задихається
- Використайте
iostatабоsar -d, щоб знайти високийawaitі високе завантаження. - Підтвердіть
cat /proc/diskstats, якщо інструменти не встановлені або зависають.
Хвилина 3–6: знайдіть джерело (PID, cgroup або VM)
- Використайте
pidstat -d, щоб знайти PIDs, які роблять I/O. - Використайте
iotopдля живої видимості, якщо він працює (іноді пропускає buffered writeback). - На хостах віртуалізації зіставте потоки QEMU з конкретними гостями через аргументи процесу libvirt/QEMU та статистику по дисках.
- Використайте PSI (
/proc/pressure/io), щоб підтвердити системний I/O‑стан очікування.
Хвилина 6–8: рішення: kill, throttle або ізоляція
- Якщо це задача бекапу, перебудови індексу або міграція: обмежте її пропускну здатність.
- Якщо це runaway‑процес: зупиніть його зараз, розбирайтеся з кореневою причиною пізніше.
- Якщо це одиночна VM: застосуйте I/O‑ліміти на гіпервізорі або шарі зберігання.
Хвилина 8–10: підтвердіть відновлення та зафіксуйте докази
- Слідкуйте, як
awaitі завантаження падають. - Зберіть
journalctl, логи ядра та короткий знімок iostat/pidstat, щоб потім виправити проблему назавжди.
Якщо зробите нічого більше, то зробіть це: знайдіть пристрій, потім знайдіть джерело. Усе інше — прикраса.
Практичні завдання: команди, вивід і рішення (12+)
Це ті ходи, які я реально використовую, коли хост «зависає», але не помер. Кожне завдання містить, що означає вивід і яке рішення приймати. Виконуйте їх по порядку, поки не отримаєте ім’я (PID або VM) і пристрій.
Завдання 1 — Подивитися iowait, load і заблоковані задачі одним поглядом
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 12 0 312844 98124 4021180 0 0 0 8240 220 410 2 1 3 94 0
0 18 0 311200 98124 4019900 0 0 0 12032 210 390 1 1 0 98 0
0 16 0 310980 98124 4019500 0 0 0 11024 205 372 1 1 1 97 0
0 20 0 310500 98124 4018400 0 0 0 14080 198 360 1 1 0 98 0
0 17 0 310300 98124 4018100 0 0 0 13056 200 365 1 1 0 98 0
Значення: стовпець b (blocked processes) високий, а wa (iowait) ~98%. Класичний підпис на те, що вузьке місце — сховище.
Рішення: не дискутуйте. Перейдіть негайно до латентності по пристрою (iostat).
Завдання 2 — Знайдіть «гарячий» пристрій за латентністю і завантаженням
cr0x@server:~$ iostat -xz 1 3
Linux 6.12.0-1-amd64 (server) 12/29/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
1.20 0.00 1.10 92.40 0.00 5.30
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
nvme0n1 0.20 8.00 0.00 0.00 2.10 40.0 420.00 67136.00 12.00 2.78 280.30 159.8 118.2 99.70
nvme1n1 18.00 2048.00 0.00 0.00 1.80 113.8 15.00 1024.00 0.00 0.00 2.40 68.3 0.1 4.10
Значення: nvme0n1 біля ~100% завантаження з величезним w_await і великою чергою (aqu-sz). Це ваш вузький пристрій.
Рішення: визначте, хто пише на nvme0n1. Також подумайте, чи це spike латентності (firmware, thermal throttling) або насичення (легітимне навантаження).
Завдання 3 — Підтвердіть системний I/O‑стоп за допомогою PSI
cr0x@server:~$ cat /proc/pressure/io
some avg10=78.43 avg60=65.12 avg300=40.02 total=184563218
full avg10=52.10 avg60=44.90 avg300=22.31 total=105331982
Значення: «full» I/O‑тиск означає, що задачі завмирали через те, що I/O не може завершитись. Це не «кілька повільних запитів», а системна проблема.
Рішення: вам дозволено вдаватися до агресивної митігації (throttle/kill), бо платять за це весь хост.
Завдання 4 — Швидко знайти топ I/O PID (і не довіряти інтуїції)
cr0x@server:~$ pidstat -d 1 5
Linux 6.12.0-1-amd64 (server) 12/29/2025 _x86_64_ (32 CPU)
03:14:01 UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
03:14:02 0 21492 0.00 65432.00 0.00 48 qemu-system-x86
03:14:02 0 31811 0.00 12160.00 0.00 20 rsync
03:14:02 0 1092 0.00 4096.00 0.00 10 jbd2/nvme0n1p2-8
03:14:02 0 25170 0.00 2048.00 0.00 8 postgres
03:14:02 UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
03:14:03 0 21492 0.00 70000.00 0.00 52 qemu-system-x86
03:14:03 0 31811 0.00 11008.00 0.00 18 rsync
Значення: найактивніший записувач — qemu-system-x86 PID 21492. Це зазвичай означає «VM — шумний сусід», а не те, що QEMU раптово вирішив нашкодити.
Рішення: зіставте цей QEMU‑процес із іменем гостя та диском. Потім або обмежте I/O гостя, або виправте те, що воно робить.
Завдання 5 — Якщо не очевидно, шукайте накопичення в D‑стані
cr0x@server:~$ ps -eo pid,state,comm,wchan:32 --sort=state | head -n 20
PID S COMMAND WCHAN
8921 D qemu-system-x86 blk_mq_get_tag
8922 D qemu-system-x86 io_schedule
8923 D qemu-system-x86 bit_wait_io
31811 D rsync io_schedule
25170 D postgres io_schedule
1092 D jbd2/nvme0n1p2-8 bit_wait_io
Значення: потоки у стані D заблоковані в блочному шарі (blk_mq_get_tag) або чекають планувальника I/O. Це узгоджується із насиченням черги на пристрої.
Рішення: ви не маєте справу з CPU‑runaway. Потрібно зменшити I/O‑навантаження або збільшити I/O‑можливості, і швидко знайти джерело.
Завдання 6 — Зіставити PID QEMU з ім’ям VM (libvirt)
cr0x@server:~$ ps -p 21492 -o pid,cmd --no-headers | sed 's/ -/\n-/g' | head -n 20
21492 /usr/bin/qemu-system-x86_64
-name guest=acct-db-03,debug-threads=on
-uuid 3bce8b54-8d13-4c4a-bd19-5e3dfe7e8a0e
-drive file=/var/lib/libvirt/images/acct-db-03.qcow2,format=qcow2,if=virtio,cache=none,aio=native
-drive file=/var/lib/libvirt/images/acct-db-03-data.raw,format=raw,if=virtio,cache=none,aio=native
Значення: тепер у вас є ідентифікатор VM: acct-db-03, і хоча б один шлях до диска. Це золото, коли треба пояснювати вплив людям.
Рішення: підтвердіть, який диск найгарячіший і чи лежить бекенд на nvme0n1. Якщо так — обмежте цей гість або зупиніть навантаження в ньому.
Завдання 7 — Знайти, який блочний пристрій відповідає файлу диска VM
cr0x@server:~$ df -h /var/lib/libvirt/images
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p2 1.8T 1.2T 526G 70% /var
Значення: образи VM розташовані на /dev/nvme0n1p2, тобто на «гарячому» NVMe. Відповідність є.
Рішення: митигувати можна на хості: обмежити I/O для VM (cgroup або libvirt), або на гості: зупинити/зменшити задачу.
Завдання 8 — Перевірити статистику блоку по домену (libvirt), щоб знайти найгучніший диск
cr0x@server:~$ virsh domblklist acct-db-03
Target Source
------------------------------------------------
vda /var/lib/libvirt/images/acct-db-03.qcow2
vdb /var/lib/libvirt/images/acct-db-03-data.raw
cr0x@server:~$ virsh domblkstat acct-db-03 vdb --human
rd_bytes 1.2 GiB
wr_bytes 842.6 GiB
rd_operations 12034
wr_operations 55210321
flush_operations 431920
wr_total_times 10421863423
Значення: vdb — важкий записувач із багатьма flush’ами. Flush’і часто посилюють латентність, бо змушують чекати на завершення.
Рішення: якщо гість виконує sync‑важкі записи (бази даних, fsync‑шторм), розгляньте throttling або переміщення на швидше/менш навантажене сховище. Також перевірте, чи не ускладнюють flush’і хостові налаштування (write cache, barriers, dm-crypt).
Завдання 9 — Перевірити, чи пристрій не відхиляє операції помилками або ресетами
cr0x@server:~$ journalctl -k -n 80 --no-pager
Dec 29 03:12:48 server kernel: nvme nvme0: I/O 1234 QID 6 timeout, aborting
Dec 29 03:12:48 server kernel: nvme nvme0: Abort status: 0x371
Dec 29 03:12:49 server kernel: nvme0n1: I/O error, dev nvme0n1, sector 1937422336 op 0x1:(WRITE) flags 0x800 phys_seg 32 prio class 0
Dec 29 03:12:50 server kernel: EXT4-fs warning (device nvme0n1p2): ext4_end_bio:345: I/O error 10 writing to inode 5513245 starting block 242177834)
Значення: таймаути і I/O‑помилки — це не «навантаження». Це проблема пристрою або шляху. За умов помилок латентність може йти вгору, а пропускна здатність падати. Ваш iowait при цьому виглядатиме так само.
Рішення: перестаньте звинувачувати навантаження. Перейдіть до апаратного/прошивкового тріажу: перевірте SMART/NVMe лог, кабелі/бэкплейн, логи контролера. За можливості виведіть диск з пулу (RAID/ZFS).
Завдання 10 — Швидка перевірка стану NVMe і лічильників помилок
cr0x@server:~$ sudo nvme smart-log /dev/nvme0
Smart Log for NVME device:nvme0 namespace-id:ffffffff
critical_warning : 0x00
temperature : 78 C
available_spare : 100%
available_spare_threshold : 10%
percentage_used : 3%
media_errors : 12
num_err_log_entries : 45
Значення: температура висока, є помилки на медіа. Thermal throttling і внутрішнє відновлення помилок можуть спричиняти величезні спайки латентності.
Рішення: розглядайте це як інцидент продуктивності й надійності. Плануйте заміну пристрою, якщо помилки продовжуються. Покращіть охолодження, якщо температура систематично висока.
Завдання 11 — Відрізнити «пристрій насичений» від «пристрій простояний, але повільний»
cr0x@server:~$ iostat -xz /dev/nvme0n1 1 2
Linux 6.12.0-1-amd64 (server) 12/29/2025 _x86_64_ (32 CPU)
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
nvme0n1 0.00 0.00 0.00 0.00 0.00 0.0 380.00 62000.00 0.00 0.00 310.00 163.2 120.0 99.90
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
nvme0n1 0.00 0.00 0.00 0.00 0.00 0.0 390.00 64000.00 0.00 0.00 295.00 164.1 118.5 99.80
Значення: це насичення (util ~100%, велика черга). Якби util був низьким, але await високим — підозрюйте переривчасті затримки, firmware‑глючення або шари вище (dm-crypt, RAID resync, NFS) замість чистого навантаження.
Рішення: якщо це насичення, зменшіть навантаження або додайте потужності (інший диск, більше шпинделів, кращий NVMe, відокремити шумні навантаження). Якщо це затримки — шукайте шар, що затримує.
Завдання 12 — Знайти файли, які атакують диск (коли є необхідність)
cr0x@server:~$ sudo lsof -p 21492 | grep -E '/var/lib/libvirt/images/|deleted' | head
qemu-system 21492 root 103u REG 259,2 34359738368 1310720 /var/lib/libvirt/images/acct-db-03-data.raw
qemu-system 21492 root 104u REG 259,2 21474836480 983040 /var/lib/libvirt/images/acct-db-03.qcow2
Значення: підтверджує, які файли образів задіяні. Воно не покаже, які блоки «гарячі», але прив’язує відповідальність до конкретного шляху.
Рішення: якщо потрібно перемістити — тепер ви знаєте, що рухати. Якщо потрібно зробити снапшот — ви знаєте, що знімати. Якщо потрібно пояснити вплив — у вас є файл і ім’я VM.
Завдання 13 — Виявити великий writeback і тиск dirty‑сторінок
cr0x@server:~$ grep -E 'Dirty|Writeback|MemAvailable' /proc/meminfo
MemAvailable: 10432124 kB
Dirty: 982432 kB
Writeback: 210944 kB
WritebackTmp: 0 kB
Значення: підвищені Dirty/Writeback вказують, що ядро штовхає буферизовані записи на диск і може застрягти за повільним I/O. Якщо dirty‑пам’ять зростає, а диск не встигає — усе стає «повільним дивним чином».
Рішення: розгляньте, чи генерує навантаження стійкі записи, що перевищують пропускну здатність пристрою, і чи підходить throttling (ionice, cgroup io.max) як міра.
Завдання 14 — Перевірити біль на рівні файлової системи (EXT4/XFS) і поведінку журналу
cr0x@server:~$ mount | grep ' on /var '
/dev/nvme0n1p2 on /var type ext4 (rw,relatime,errors=remount-ro)
cr0x@server:~$ dmesg | tail -n 20
[12345.678901] EXT4-fs (nvme0n1p2): Delayed block allocation failed for inode 5513245 at logical offset 123456 with max blocks 2 with error 5
[12345.678910] EXT4-fs (nvme0n1p2): This should not happen!! Data will be lost
Значення: попередження файлової системи плюс I/O‑помилки — це «зупини світ» події. Навіть без помилок, поява журнал‑потоків (наприклад, jbd2) у pidstat — підказка, що записи форсують метадані та коміти.
Рішення: якщо є помилки — ставтеся до цього як до відмови сховища. Якщо помилок немає, а flush’ів/commit’ів багато — зосередьтесь на патерні навантаження (fsync‑шторм, дрібні випадкові записи) і конфігурації сховища (write cache, barriers, режим кешування віртуалізації).
Завдання 15 — Коли потрібні жорсткі докази: підміряйте блок‑I/O за допомогою blktrace
cr0x@server:~$ sudo blktrace -d /dev/nvme0n1 -w 10 -o - | sudo blkparse -i - | head -n 20
8,0 0 1 0.000000000 21492 Q WS 1937422336 + 128 [qemu-system-x86]
8,0 0 2 0.000012345 21492 G WS 1937422336 + 128 [qemu-system-x86]
8,0 0 3 0.000056789 21492 I WS 1937422336 + 128 [qemu-system-x86]
8,0 0 4 0.310123456 21492 D WS 1937422336 + 128 [qemu-system-x86]
8,0 0 5 0.650987654 21492 C WS 1937422336 + 128 [qemu-system-x86]
Значення: ви можете атрибутувати I/O на блочному шарі до PID (тут QEMU). Зверніть увагу на проміжок часу між запитом і завершенням; це ваша сирова латентність.
Рішення: якщо потрібно переконати когось, що «VM справді винна», це — доказ для суду. Також корисно, коли кілька PIDs залучені й userland‑інструменти не сходяться.
Завдання 16 — Швидке митигування: обмежити шумну cgroup (systemd) через io.max
cr0x@server:~$ systemctl status libvirtd | head -n 5
● libvirtd.service - Virtualization daemon
Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled)
Active: active (running) since Mon 2025-12-29 02:11:03 UTC; 1h 03min ago
cr0x@server:~$ sudo systemctl set-property --runtime machine-qemu\\x2dacct\\x2ddb\\x2d03.scope IOReadBandwidthMax=/dev/nvme0n1 10M IOWriteBandwidthMax=/dev/nvme0n1 20M
Значення: ви щойно застосували runtime‑ліміти I/O‑пропускної здатності до systemd‑scope цієї VM (назви різняться; підтвердіть точну назву scope на вашому хості). Це зменшить здатність VM виснажувати хост.
Рішення: використовуйте це, коли важливіша стабільність хоста, ніж швидкість одного гостя. Потім заплануйте постійне рішення: ізолюйте навантаження, налаштуйте DB, або перемістіть гостя на виділене сховище.
Жарт №2: Обмежити шумну VM — це як прикрутити колеса до візка. Це не зробить його елегантним, але принаймні перестане кричати.
Факти й історія, що допоможуть дебажити швидше
Знання кількох «чому так» фактів врятує від марних гонок за примарами. Ось ті, що дійсно важать, коли ви дивитесь на iowait о 03:00.
- Linux iowait — це стан обліку CPU, а не метрика диска. Він може бути високим, навіть коли диск не повністю завантажений, особливо при переривчастих затримках або глибоких чергах ядра.
- Старе поле
svctmв iostat стало ненадійним для сучасних пристроїв і multi‑queue. Люди й досі цитують його, як якби це була євангелія. Не варто. - blk-mq (multi‑queue block layer) змінило інтуїцію «одна черга на пристрій». NVMe і сучасне сховище можуть мати багато черг; поведінка насичення виглядає інакше, ніж у старих SATA.
- CFQ помер, BFQ прийшов, і
mq-deadlineстав стандартним вибором для багатьох SSD. Вибір планувальника може змінити хвостову латентність при змішаних навантаженнях. - PSI (Pressure Stall Information) — відносно новий у порівнянні з класичними інструментами. Він показує «наскільки система зависає», а не тільки «наскільки зайнята», що ближче до болю користувачів.
- Writeback кешування може приховувати початок інциденту. Ви можете буферизувати записи в RAM доти, доки не перестанете встигати, а потім платите відсотки: довгі flush‑штормі.
- Віртуалізація додає додатковий стек планування. Гість вважає, що виконує «розумний» fsync; хост перетворює це на реальні flush’і; нижній шар вирішує, що настав час для garbage collection.
- Thermal throttling NVMe — це реальний продакшн‑режим відмови. Високі послідовні записи можуть довести диски до троттлінгу, спричиняючи драматичне зростання латентності без очевидних помилок спочатку.
- RAID‑resync і scrubs можуть створити цілком легітимний I/O‑DoS. Для цього не потрібен баг. Просто невдалий час.
Якщо це VM: зіставлення хостового I/O із «шумним» гостем
На хості віртуалізації найпоширеніша неправильна дія — вважати QEMU винуватцем. QEMU — це кур’єр. Ваше справжнє питання: яке гостьове навантаження насичує який хостовий пристрій, і чи це очікувана пакетна робота або випадкова «вистрілена нога»?
Як «шумний VM» виглядає на хості
pidstat -dпоказує один або кількаqemu-system-*PIDs, що домінують у записах.iostatпоказує один пристрій з великою чергою (aqu-sz) і високим await.- Load average росте, але CPU в основному idle за винятком iowait.
- Інші VMs скаржаться: «диск повільний» або «база зависла», хоча вони мало що роблять.
Як чисто зіставити потоки QEMU з доменом
Якщо ви використовуєте libvirt, зіставлення можна зробити через:
- командний рядок процесу QEMU (
-name guest=...) virsh domblkstatпо кожному диску- systemd scope‑units під
machine.slice(назви залежать від налаштувань)
Після отримання імені гостя у вас є варіанти:
- Мітигація на стороні гостя: призупинити бекап, зменшити паралелізм, налаштувати точки контрольних записів у БД, зупинити перебудову індексу, обмежити компактування.
- Мітигація на стороні хоста: застосувати I/O‑ліміти через cgroup v2 (
io.max/ systemd‑властивості), або налаштування libvirt I/O (якщо вже є). - Структурне рішення: перемістити VM на виділене сховище, розділити OS‑диск від data‑диска, або відокремити «пакетні» навантаження від «чутливих до латентності» VMs.
Коли VM не робить «так багато», але все одно ламає хост
Тут важливі flush’і, sync‑запити і патерни, що працюють з метаданими. Гість, який робить помірну кількість транзакцій з fsync, може створити величезний тиск, якщо стек під ним перетворює кожен fsync на дорогий flush через dm-crypt, RAID або диск, що виконує внутрішній GC.
Слідкуйте за:
- високою кількістю
flush_operationsвvirsh domblkstat - змінами конфігурації БД, що підвищують гарантії надійності
- змінами параметрів монтування FS у гості
- змінами в режимі кешування хоста (наприклад,
cache=nonevswriteback)
Тріаж шару зберігання: NVMe, RAID, dm-crypt, ZFS, мережа
Після того як ви ідентифікували шумний процес/VM, треба вирішити, чи справжнє виправлення — «припинити це» або «стек зберігання хворий». Найшвидше — розпізнати типові режими відмов за їхньою телеметрією.
NVMe: швидко, доки не перестане
Інциденти з NVMe часто діляться на два набори: насичення (легітимне навантаження) і спайки латентності (апарат/прошивка/термічне). Насичення — банальне. Спайки латентності — драматичні.
Що перевіряти:
- Температура і помилки через
nvme smart-log - Логи ядра на наявність таймаутів/ресетів
- Util проти await: якщо util низький, але await високий — підозрюйте stall’и, а не обмеження пропускної здатності
mdadm RAID: resync — це запланований інцидент, якщо ви його дозволите
Software RAID може працювати стабільно місяцями, а потім rebuild або scrub починається, і ваш «стабільний хост» перетворюється на урок про спільні ресурси. I/O rebuild конкурує з усім іншим.
cr0x@server:~$ cat /proc/mdstat
Personalities : [raid1] [raid10]
md0 : active raid1 sda1[0] sdb1[1]
976630336 blocks super 1.2 [2/2] [UU]
[===>.................] resync = 18.3% (178944000/976630336) finish=123.4min speed=107000K/sec
unused devices: <none>
Значення: resync активний. Це може спричинити iowait навіть якщо робоче навантаження не змінилось.
Рішення: обмежте швидкість rebuild, якщо це шкодить продакшену, або плануйте вікна для resync. Не «оптимізуйте», дозволяючи rebuild бути безконтрольним на спільних дисках.
dm-crypt: шифрування не безкоштовне, і semantics flush важливі
dm-crypt додає витрати CPU і може вплинути на латентність при sync‑важких навантаженнях. На сучасних CPU зазвичай нормально, але це може зробити хвостову латентність менш приємною у певних патернах.
cr0x@server:~$ lsblk -o NAME,TYPE,FSTYPE,SIZE,MOUNTPOINTS
nvme0n1 disk 1.8T
├─nvme0n1p1 part vfat 512M /boot/efi
└─nvme0n1p2 part crypto_LUKS 1.8T
└─cryptvar crypt ext4 1.8T /var
Значення: ваша «гаряча» ФС лежить поверх dm-crypt. Це не автоматично погано. Це натяк, що flush‑важкі навантаження можуть платити додаткову ціну.
Рішення: якщо flush‑шторм вбиває вас, тестуйте на реалістичних навантаженнях і розгляньте відокремлення sync‑важких навантажень на виділені пристрої або перегляд налаштувань кешування/I/O. Не відключайте шифрування в паніці, якщо вам важливі вимоги відповідності.
ZFS: «txg sync» — удар у лице
ZFS може дати відмінну продуктивність, але також навчити про write amplification. Частий iowait‑сценарій — періодичні затримки під час txg sync, коли пул перевантажений або неправильно налаштований під навантаження.
cr0x@server:~$ zpool iostat -v 1 3
capacity operations bandwidth
pool alloc free read write read write
rpool 1.20T 600G 5 950 200K 120M
mirror 1.20T 600G 5 950 200K 120M
nvme0n1p3 - - 2 480 100K 60M
nvme1n1p3 - - 3 470 100K 60M
Значення: інтенсивні записи; якщо латентність погана, перевіряйте sync‑записи і використання SLOG, recordsize, compression та заповнення пулу.
Рішення: якщо VM‑база даних робить sync‑записи, розгляньте окремий SLOG‑пристрій (з захистом від втрати живлення) або зміну поведінки додатка. Не «виправляйте» це відключенням sync, якщо не готові до втрати даних.
Мережеве сховище (NFS/iSCSI): коли «диск» насправді мережа
NFS може породжувати iowait, який виглядає як насичення локального диска. Хост чекає на завершення I/O, але ці завершення залежать від мережевої латентності, навантаження сервера або репередач.
cr0x@server:~$ mount | grep nfs
10.0.0.20:/export/vm-images on /var/lib/libvirt/images type nfs4 (rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2)
cr0x@server:~$ nfsstat -c | head -n 20
Client rpc stats:
calls retrans authrefrsh
1234567 3456 123
Client nfs v4:
null read write commit open
0 234567 345678 4567 1234
Значення: retransmits ненульові і зростають; commit’и є; «hard» монтування означає, що задачі можуть висіти, доки сервер не відреагує.
Рішення: перевірте мережеві помилки, навантаження NFS‑сервера і розгляньте ізоляцію чутливих до латентності VM від мережево‑бекендового сховища. Якщо хост «зависає» через NFS — поводьтесь з цим як з відмовою залежності, а не локального диска.
Три корпоративні історії з польових
1) Інцидент через хибне припущення: «iowait означає, що диск на максимумі»
Одна команда платформи мала кластер віртуалізації на Debian, який час від часу входив у режим «всім повільно». На черговому інциденті on‑call побачив iowait 90–100%, глянув на дашборд із помірною пропускною здатністю диску і припустив, що масив в порядку, бо «він навіть не витискає бендвіду». Тож вони зосередились на CPU і пам’яті. Tюнінгували swappiness. Перезапускали сервіси. Навіть звинувачували недавній деплой, бо люди під стресом так роблять.
Тим часом кластер продовжував зависати хвилями: SSH‑сесії зависали, VMs таймаутили, потім магічно відновлювалися. Виглядало як транзієнтна зовнішня проблема. Команда відправила тикет вендору сховища. Вендор попросив латентні числа. Ніхто їх не мав у тригері.
Справжня проблема була у хвостовій латентності від переривчастих stall’ів на NVMe через thermal throttling. Util і throughput не були проблемою; проблемою був час завершення (completion time). Під час stall’ів черги наростали, задачі блокувались, iowait підскакував, а потім backlog стікав. Графіки пропускної здатності залишались «гідними», бо середній MB/s не відображав секундні паузи.
Після перегляду iostat -xz і NVMe smart log все стало очевидним: високі температури, log‑помилки, await у сотнях мс. Виправлення було непоказним: покращити циркуляцію повітря в шасі, оновити прошивку і замінити найгірший диск. Також додали алерти на латентність і PSI, а не тільки на пропускну здатність. Наступного разу алерт вже казав: «IO full pressure high; nvme0 await 280ms.» Суперечки завершилися до їх початку.
2) Оптимізація, що відбилася бумерангом: «Зробимо бекапи швидшими»
Одна ops‑група захотіла скоротити вікно бекапів VM‑образів. Вони перейшли з повільнішого rsync‑підходу на новий метод із кількома паралельними потоками та агресивними розмірами блоків. На папері — чудово: бекапи швидші, менше часу на вікно, сучасніше. Роллаутили по всіх гіпервізорах у п’ятницю, бо, звісно.
Першого вікенду кластер опинився в дивному стані: бекапи завершувалися швидко, але під час вікна клієнтські VMs ставали не відзивчивими. Латентні сервіси фіксували таймаути. Гіпервізори показували iowait у піковому стані. Деякі гості були «припинені» watchdog‑ами, бо віртуальні диски перестали вчасно відповідати.
Ця «оптимізація» фактично була розподіленим DoS проти власного сховища. Паралельні потоки наситили підлягаючу чергу пристрою і загнали контролер в найгірший режим для змішаних навантажень. Бекапи закінчились швидко, бо кластер пожертвував рештою, щоби їх пришвидшити.
Виправлення — трактувати бекапи як фонове навантаження, а не гонку. Вони ввели I/O‑throttling для бекапів і обмеження конкуренції на хост. Бекапи стали довшими, але бізнес перестав втрачати вихідні. Також відокремили «golden image backups» від «гарячих DB VMs» на різні рівні зберігання. Урок був простий: зробити одне завдання швидшим, позичивши латентність у всіх інших, — це не оптимізація, а перерозподіл болю.
3) Нудна, але правильна практика, що врятувала день: перехідні I/O‑гардрейли на хості
Інша компанія керувала флотом Debian‑віртуалізації з чітким правилом: у кожного VM‑scope були визначені I/O‑гардрейли. Нічого драматичного, просто розумні дефолти у cgroup v2: обмеження пропускної здатності і IOPS, налаштовані під класи навантажень. Спочатку це викликало закочені очі. Девелопери хотіли «без обмежень». Менеджмент хотів «максимального використання». SRE хотіли «без сюрпризів». SRE тихо перемогли.
Одного дня команда запустила трансформацію даних у VM. Вона почала виконувати великі write‑heavy операції із частими fsync. У більшості середовищ це момент, коли хост перетворюється на цеглину і всі вчать нові слова. Тут міграція VM затрималась, бо дійшла до свого ліміту. Інші VMs залишились у нормі. Хост залишився відзивчивим. Ніхто не запалився.
Міграція завершилася пізніше, ніж розробник очікував, тому він поцікавився. SRE витягли статистику cgroup і показали I/O‑throttling. Пояснили, що альтернатива — весь гіпервізор у iowait‑пеклі і падіння сервісів.
Нічого героїчного не сталось. Ось у чому суть. Нудна практика — гардрейли — перетворила потенційний інцидент кластера у лише трохи нещасливого інженера й повільнішу міграцію. Такі перемоги цінуються після перших опіків.
Типові помилки: симптоми → корінь → виправлення
Саме тут більшість команд марнує години. Патерни повторюються, як і виправлення.
1) «iowait 100%, значить диск на максимумі»
Симптом: iowait високий, throughput помірний, система «зависає» хвилями.
Корінь: спайки латентності (thermal throttling, firmware hiccup, path resets) а не сталий bandwidth saturation.
Виправлення: дивіться await, aqu-sz, PSI, логи ядра; перевірте NVMe temp/errors; оновіть прошивку і охолодження; замініть несправне медіа.
2) «iotop нічого не показує, отже це не I/O»
Симптом: iowait високий, iostat показує записи, iotop тихий.
Корінь: буферизовані записи, які скидає kernel (writeback), або I/O атрибутується іншим потокам (QEMU, jbd2, kswapd).
Виправлення: використайте pidstat -d, перевірте Dirty/Writeback у /proc/meminfo, огляньте kernel‑threads у стані D.
3) «Load average високий, отже CPU проблема»
Симптом: load зростає, CPU idle високий, iowait високий.
Корінь: load включає задачі, заблоковані в uninterruptible I/O sleep; це не тільки CPU‑метрика.
Виправлення: корелюйте load із заблокованими задачами (стовпець b у vmstat) і станом D (ps). Трактуйте як I/O.
4) «Це база даних» (без доказів)
Симптом: запити БД таймаутять під час інциденту; всі звинувачують БД.
Корінь: БД — жертва насиченої дискової черги, викликаної іншим навантаженням (бекап, міграція, ротація логів) або сусідом у VM.
Виправлення: доведіть джерело за допомогою pidstat і per‑VM статистики; ізолюйте сховище БД; введіть I/O‑ліміти для пакетних задач.
5) «Виправимо, змінивши I/O‑планувальник»
Симптом: випадкові спайки латентності при змішаних навантаженнях; команда сперечається про планувальники.
Корінь: вибір планувальника може допомогти хвостовій латентності, але не виправить несправний диск, resync‑шторм чи одну VM, що насичує пристрій.
Виправлення: спочатку ідентифікуйте пристрій і винного; потім тестуйте зміни планувальника на реалістичних навантаженнях з планом відкату.
6) «Призупинимо VM і все одразу відновиться»
Симптом: призупинення/вбивство топового писача не одразу відновлює відзивчивість.
Корінь: backlog ще стікає; journal commits; RAID resync; writeback flush; або відновлення файлової системи.
Виправлення: зачекайте, поки черги спустошаться, слідкуйте за iostat; перевірте ongoing resync/scrub; дивіться логи ядра на помилки.
7) «Відключити sync — це нормально, швидше буде»
Симптом: продуктивність покращується після відключення sync в налаштуваннях сховища/додатка.
Корінь: ви обміняли надійність на швидкість; консистентність після збою може бути втрачена.
Виправлення: використайте відповідне обладнання (PLP NVMe, SLOG), тюнінгуйте навантаження або погодьтеся на повільніший I/O. Не впроваджуйте зміни збереження даних у прод без явного рішення.
Контрольні списки / покроковий план
Чекліст A: 10‑хвилинне «назвіть винного»
- Запустіть
vmstat 1 5: підтвердіть високийwaі багато заблокованих задач (b). - Запустіть
iostat -xz 1 3: ідентифікуйте «гарячий» пристрій заawait,aqu-szі%util. - Перевірте
/proc/pressure/io: підтвердіть вплив на систему (високий «full»). - Запустіть
pidstat -d 1 5: знайдіть топ read/write PIDs. - Якщо топ‑PID — QEMU: зіставте з іменем VM через
psі/або інструменти libvirt. - Підтвердіть мапінг сховища:
dfна шлях образу і/абоlsblkдля стеку (dm-crypt, LVM). - Митигуйте:
- Зупиніть або обмежте навантаження.
- Застосуйте cgroup I/O‑ліміти для scope.
- Призупиніть VM тільки якщо необхідно, і будьте готові до часу спустошення черги.
- Підтвердіть відновлення:
iostatawait і util нормалізуються; PSI full падає. - Забезпечте докази: знімок iostat/pidstat, логи ядра, VM‑статистика.
Чекліст B: Дерево рішень «апарат чи навантаження?»
- Логи ядра показують таймаути/ресети/I/O‑помилки? Спочатку тріаж апарат/шлях.
- Device util ~100% з великою чергою? Ймовірно насичення; знайдіть топ‑писача і обмежте/ізолюйте.
- Util низький, але await високий? Шукайте stall’и: thermal throttling, firmware, RAID‑події, мережеві затримки.
- Flush’ів дуже багато? Шукайте sync‑важкі додатки, barriers, накладні витрати dm-crypt, поведінку ZFS.
- Лише одна VM постраждала? Проблема специфічна для гостя; все ж перевірте, чи вона не виснажує інших через спільну чергу.
- Усе постраждало, включно з несуміжними сервісами? Спільне вузьке місце на рівні хоста; введіть гардрейли і ізолюйте критичні навантаження.
Чекліст C: Постійне запобігання (що впровадити після інциденту)
- Додайте моніторинг: per‑device await, глибина черги, PSI I/O «full», і температура NVMe.
- Встановіть розумні дефолти I/O через cgroup v2 для VMs і пакетних задач.
- Відокремте зберігання для «чутливих до латентності» і для «масових записів».
- Плануйте RAID rebuild/scrub і ZFS scrub поза піковими годинами; обмежуйте, якщо потрібно.
- Документуйте, які навантаження мають право робити важкий I/O і коли.
FAQ
1) Чи 100% iowait завжди означає проблему з диском?
Ні. Це проблема завершення I/O. Диск може бути локальним SSD, RAID, стеком dm-crypt, мережевим сховищем або контролером, що періодично зависає. Завжди визначайте пристрій і перевіряйте латентність.
2) Чому хост «зависає», хоча CPU в основному idle?
Бо потрібні вам потоки заблоковані в uninterruptible sleep, чекаючи I/O. Idle CPU не допоможе, коли ядро чекає на завершення блочного шару.
3) Який найшвидший спосіб знайти винний PID?
pidstat -d 1 — найшвидший надійний інструмент для I/O‑рейтів по PID. iotop корисний, але може пропускати writeback і іноді вводить в оману.
4) Як знайти, яка VM це робить на KVM/libvirt‑хості?
Використайте pidstat, щоб знайти QEMU‑PID, потім подивіться командний рядок QEMU на -name guest=... і підтвердіть через virsh domblkstat, який диск пише.
5) iostat показує високий await, але низький %util. Як так буває?
Тому що пристрій може періодично «зависати» або завершувати I/O поривами, або вузьке місце знаходиться вище (мережеве сховище, ресети контролера, відновлення помилок). Низький util із високою латентністю — червоний прапорець для переривчастих stall’ів, а не «занадто багато навантаження».
6) Чи варто змінити I/O‑планувальник, щоб вирішити iowait‑зависання?
Не як перший крок. Зміни планувальника можуть допомогти хвостовій латентності при змішаних навантаженнях, але не виріжуть несправний диск, resync‑шторм або одну VM, що насичує пристрій. Спочатку діагностуйте, потім тестуйте зміни з можливістю відкату.
7) Яке найбезпечніше митигування, коли одна VM шумить?
Обмежте її через cgroup I/O‑ліміти або libvirt I/O‑тюнінг, щоб хост залишався відзивчивим. Вбити VM також працює, але ризикованіше, якщо ви не знаєте, що в ній відбувається (бази даних, незавершені записі).
8) Чи може RAM‑кеш приховувати проблеми з I/O?
Так. Буферизовані записи можуть робити вигляд, що все гаразд, допоки не почнеться writeback і диск не встигатиме. Тоді настане flush‑шторм і хост заплатить рахунок.
9) Чому flush’і/fsync так драматично уповільнюють систему?
Вони змушують зберігати порядок і гарантії надійності. Якщо стек під ними (RAID, dm-crypt, прошивка SSD) робить flush дорогим, навантаження швидко стане латентно‑зв’язаним навіть при помірній пропускній здатності.
10) Як зрозуміти, чи варто замінити диск?
Якщо в логах ядра є таймаути/ресети, або NVMe SMART показує зростання media errors і записів помилок, розглядайте це як питання надійності. Інциденти продуктивності часто переростають у інциденти втрати даних, якщо їх ігнорувати.
Висновок: практичні наступні кроки
Коли Debian 13 досягає 100% iowait і хост «зависає», не ставтеся до цього як до нерозв’язної таємниці. Сприймайте це як задачу ідентифікації з секундоміром. Назвіть пристрій. Назвіть джерело. Митигуйте. Зафіксуйте докази. Потім виправте структуру, що дозволила одному навантаженню монополізувати спільний I/O.
Зробіть наступні кроки:
- Додайте алерти на per‑device
awaitі PSI I/O «full», а не тільки на throughput. - Впровадьте I/O‑гардрейли для VM і пакетних задач (cgroup v2), щоб один гість не міг «вивести з ладу» хост.
- Відокремте масові записи від сервісів, чутливих до латентності, на рівні зберігання.
- Регулярно переглядайте логи ядра і NVMe‑стан; замінюйте підозрілі диски до того, як вони навчать вас смирення.
Найкращий інцидент з iowait — той, де нічого цікавого не сталося, бо ви місяці тому обмежили шумного сусіда. Прагніть нудності.