Debian 13: 100% iowait — хост «зависає» — знайдіть шумний процес/VM за 10 хвилин

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

Ваш хост 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 хвилин:

  1. Який пристрій? (nvme0n1? md0? dm-crypt? NFS‑монтування?)
  2. Який тип навантаження? (латентність? насичення? повторні спроби? flush/sync?)
  3. Яке джерело? (PID? контейнер? VM/гост?)
  4. Яка дія? (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.

  1. Linux iowait — це стан обліку CPU, а не метрика диска. Він може бути високим, навіть коли диск не повністю завантажений, особливо при переривчастих затримках або глибоких чергах ядра.
  2. Старе поле svctm в iostat стало ненадійним для сучасних пристроїв і multi‑queue. Люди й досі цитують його, як якби це була євангелія. Не варто.
  3. blk-mq (multi‑queue block layer) змінило інтуїцію «одна черга на пристрій». NVMe і сучасне сховище можуть мати багато черг; поведінка насичення виглядає інакше, ніж у старих SATA.
  4. CFQ помер, BFQ прийшов, і mq-deadline став стандартним вибором для багатьох SSD. Вибір планувальника може змінити хвостову латентність при змішаних навантаженнях.
  5. PSI (Pressure Stall Information) — відносно новий у порівнянні з класичними інструментами. Він показує «наскільки система зависає», а не тільки «наскільки зайнята», що ближче до болю користувачів.
  6. Writeback кешування може приховувати початок інциденту. Ви можете буферизувати записи в RAM доти, доки не перестанете встигати, а потім платите відсотки: довгі flush‑штормі.
  7. Віртуалізація додає додатковий стек планування. Гість вважає, що виконує «розумний» fsync; хост перетворює це на реальні flush’і; нижній шар вирішує, що настав час для garbage collection.
  8. Thermal throttling NVMe — це реальний продакшн‑режим відмови. Високі послідовні записи можуть довести диски до троттлінгу, спричиняючи драматичне зростання латентності без очевидних помилок спочатку.
  9. 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=none vs writeback)

Тріаж шару зберігання: 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‑хвилинне «назвіть винного»

  1. Запустіть vmstat 1 5: підтвердіть високий wa і багато заблокованих задач (b).
  2. Запустіть iostat -xz 1 3: ідентифікуйте «гарячий» пристрій за await, aqu-sz і %util.
  3. Перевірте /proc/pressure/io: підтвердіть вплив на систему (високий «full»).
  4. Запустіть pidstat -d 1 5: знайдіть топ read/write PIDs.
  5. Якщо топ‑PID — QEMU: зіставте з іменем VM через ps і/або інструменти libvirt.
  6. Підтвердіть мапінг сховища: df на шлях образу і/або lsblk для стеку (dm-crypt, LVM).
  7. Митигуйте:
    • Зупиніть або обмежте навантаження.
    • Застосуйте cgroup I/O‑ліміти для scope.
    • Призупиніть VM тільки якщо необхідно, і будьте готові до часу спустошення черги.
  8. Підтвердіть відновлення: iostat await і util нормалізуються; PSI full падає.
  9. Забезпечте докази: знімок iostat/pidstat, логи ядра, VM‑статистика.

Чекліст B: Дерево рішень «апарат чи навантаження?»

  1. Логи ядра показують таймаути/ресети/I/O‑помилки? Спочатку тріаж апарат/шлях.
  2. Device util ~100% з великою чергою? Ймовірно насичення; знайдіть топ‑писача і обмежте/ізолюйте.
  3. Util низький, але await високий? Шукайте stall’и: thermal throttling, firmware, RAID‑події, мережеві затримки.
  4. Flush’ів дуже багато? Шукайте sync‑важкі додатки, barriers, накладні витрати dm-crypt, поведінку ZFS.
  5. Лише одна VM постраждала? Проблема специфічна для гостя; все ж перевірте, чи вона не виснажує інших через спільну чергу.
  6. Усе постраждало, включно з несуміжними сервісами? Спільне вузьке місце на рівні хоста; введіть гардрейли і ізолюйте критичні навантаження.

Чекліст 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.

Зробіть наступні кроки:

  1. Додайте алерти на per‑device await і PSI I/O «full», а не тільки на throughput.
  2. Впровадьте I/O‑гардрейли для VM і пакетних задач (cgroup v2), щоб один гість не міг «вивести з ладу» хост.
  3. Відокремте масові записи від сервісів, чутливих до латентності, на рівні зберігання.
  4. Регулярно переглядайте логи ядра і NVMe‑стан; замінюйте підозрілі диски до того, як вони навчать вас смирення.

Найкращий інцидент з iowait — той, де нічого цікавого не сталося, бо ви місяці тому обмежили шумного сусіда. Прагніть нудності.

← Попередня
VPN повільніший, ніж очікували: діагностика CPU роутера, крипто та MSS clamping як слід
Наступна →
Плутанина з AllowedIPs у WireGuard: чому трафік не йде туди, куди ви очікуєте (і як це виправити)

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