Ubuntu 24.04: «зависання» диска під навантаженням — налаштування таймаутів, що запобігають повним зависанням (випадок №90)

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

Коли диск починає гальмувати, система не повинна філософствувати. Проте під важким I/O машини на Ubuntu 24.04 можуть виглядати «завислими», навіть якщо CPU ледве завантажений, а пам’ять у порядку — бо ядро чемно чекає на сховище, яке перестало бути чемним.

Це не просто «продуктивність». Це життєздатність. Різницю між спайком латентності й повним простоєм послуги часто створюють кілька таймаутів, очікувань у чергах і шляхів відновлення, які ви або налаштували, або успадкували випадково.

Як виглядає «зависання» диска в Ubuntu 24.04

«Зависання» — недбалий термін, тому уточнимо. У цьому випадку машина не впала. Вона застрягла, чекаючи завершення I/O. Це означає:

  • SSH-підключення працює, але команди на кшталт ls або df зависають при зверненні до уражених монтувань.
  • Середнє навантаження (load average) зростає, але завантаження CPU виглядає нудним. Це виконувані завдання чекають через заблокований I/O, а не «штурм обчислень».
  • Юніти systemd перестають реагувати на зупинку/перезапуск. Вони застрягли в переривному сні (стан D).
  • Логи ядра згадують таймаути, скидання, «blocked for more than 120 seconds» або очікування журналу файлової системи.

Ціль не в тому, щоб диски ніколи не гальмували. Ціль: коли диски стають повільними або зникають, система повинна швидко відновитися, відмовлятися в запитах швидко і не клинити, намагаючись допомогти.

Операційна істина: ядро може чекати довше, ніж ваш бізнес може дозволити. Ваше завдання — узгодити ці годинники.

Швидкий план діагностики

Коли продакшн плавиться, не починайте з редагування sysctls. Почніть з відповіді на три питання: що саме застрягло, де воно застрягло і чому відновлення не відбувається.

Спочатку: підтвердьте, що це I/O wait, і визначте пристрій

  • Перевірте iowait та заблоковані задачі.
  • Знайдіть, які монтування та які блочні пристрої задіяні.
  • Шукайте очевидні повідомлення ядра про скидання/таймаути.

По-друге: вирішіть, чи це «спайк латентності», чи «відмова шляху/пристрою»

  • Спайк латентності: I/O завершується зрештою; черги будуються; таймаути можуть не спрацювати.
  • Відмова: команди зависають безкінечно; multipath може чекати вічно; драйвер може повторюватися хвилинами.

По-третє: перевірте політику, що погіршує стаґ

  • Multipath: queue_if_no_path може перетворити транзитний бліп SAN на блокування додатка.
  • Таймаути пристрою: таймаути SCSI або NVMe визначають, скільки ядро намагається перед тим, як помилитися або скинути.
  • Поводження файлової системи: коміти журналу та операції з метаданими можуть послідовно блокувати несуміжну роботу.
  • Таймаути сервісів: systemd може чекати занадто довго, щоб швидко відмовити або перезапустити.

Отримайте факти швидко, потім крутіть потрібну ручку. Під тиском людям подобається крутити випадкові ручки. Так ви отримаєте систему, яка відмовляється швидше, ніж відновлюється.

Факти й контекст, що змінюють підхід до налагодження

Ось кілька конкретних пунктів — деякі історичні — які пояснюють, чому проблеми «зависання диска» поводяться так, як вони поводяться:

  1. Блоковий I/O в Linux може блокуватися в переривному сні (стан D), тобто сигнали не вб’ють процес. Ось чому kill -9 виглядає безсилим.
  2. Обробка помилок SCSI винахідливо терпляча. Вона сильно намагається відновити без втрати даних — це круто, поки вашим додаткам потрібна швидка відмова.
  3. Типовий поріг попереджень про «blocked task» (часто 120s) — це не таймаут; це скарга. Робота може залишатися заблокованою довше після попередження.
  4. Multipath створювався, щоб пережити нестійкі fabric. Функції на кшталт «queue when no paths» мали зберегти записи під час втрати шляху, але вони можуть заморозити простір користувача.
  5. NCQ і глибокі черги (SATA/SAS) покращили пропускну здатність, але великі черги можуть підсилити хвостову латентність під конкуренцією. Одна повільна команда може стояти попереду багатьох інших.
  6. NVMe приніс швидку звітність помилок і скидання контролерів порівняно зі старим SATA, але політика скидання/повторного підключення все ще важлива, особливо з урахуванням особливостей PCIe.
  7. Журналювання ext4 існує для збереження цілісності метаданих. Під затримками сховища коміти журналу можуть блокувати операції, які виглядають несуміжними, наприклад створення файлу в іншому каталозі.
  8. Політики кешування запису були полем битви надійності десятиліттями: швидкі кеші приховують латентність доти, доки не перестають, а тоді це виливається у величезні спайки.
  9. Віртуалізація додала шари чергування (гостьовий блочний шар, virtio-черги, черги HBA хоста, черги масиву). Хвостова латентність компонується через шари.

Сухо-іронічна перевірка реальності: диски не «зависа́ють». Вони входять у тривалі стосунки з вашим ядром, а ваше ядро не вірить у швидку капітуляцію.

Таймаути: модель, яку потрібно тримати в голові

Не існує єдиного «таймауту диска». Є кілька таймерів і політик, що нашаровуються, інколи мультиплікативно:

  • Таймаути команд на рівні пристрою (SCSI device_timeout / таймаут на пристрій; таймаути контролера NVMe).
  • Відновлення транспорту/лінку (скидання SAS-лінків, події FC fabric, таймаути сесії iSCSI, поведінка TCP-переспроби).
  • Політика mapper (поведінка черги dm-multipath, fast_io_fail_tmo, dev_loss_tmo).
  • Поведінка RAID-шару (таймаути mdraid; прошивка контролера; кеш запису).
  • Таймаути файлової системи/журналу (не завжди явні, але інтервали commit і поведінка sync).
  • Таймаути додатків/сервісів (таймаути юнітів systemd, таймаути клієнтських запитів, таймаути запитів до БД).

Коли шлях до диска порваний, ядро може продовжувати повторювати спроби, перемаповувати й чекати. Це може бути вірним за замовчуванням для цілісності даних. У продакшні ви маєте вирішити: ви віддаєте перевагу чеканню чи відмові? Для запису бази даних чекання може бути безпечнішим. Для статeless API вузла краще швидка відмова й переразподіл.

Цитата, яка має бути на кожному онкол-рейшні: «Надія — не стратегія.» — General Gordon R. Sullivan

Хитрість у тому, щоб обрати значення таймаутів, що відповідають часу відновлення вашого оточення. Якщо ваш SAN переключається 15–30 секунд, не налаштовуйте політику, що затримуєсь безкінечно. Якщо прошивка SSD інколи потребує 5 секунд, не ставте таймаути в 1 секунду й не викликайте постійні скидання.

Практичні завдання (команди, що означає вивід і рішення)

Вам потрібні реальні команди, а не інтуїція. Ці завдання впорядковані приблизно від «безпечних і швидких» до «це змінює поведінку». Запускайте їх на Ubuntu 24.04; більшість вимагає root.

Завдання 1: Підтвердіть високий iowait і тиск черги виконання

cr0x@server:~$ mpstat -P ALL 1 5
Linux 6.8.0-xx-generic (server)  12/31/2025  _x86_64_  (16 CPU)

12:00:01 AM  CPU   %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
12:00:02 AM  all   2.10  0.00  1.20   41.30 0.00  0.20   0.00   0.00    0.00  55.00

Значення: iowait понад 40% свідчить, що CPU майже вільні, бо вони чекають на сховище, а не через «завантаженість» системи.

Рішення: Перейдіть до ідентифікації пристрою. Не налаштовуйте CPU. Ще не ганяйтеся за «load average».

Завдання 2: Визначте процеси в стані D

cr0x@server:~$ ps -eo pid,stat,comm,wchan:32 | awk '$2 ~ /D/ {print}'
23144 D    postgres  io_schedule
28901 D    rsync     ext4_sync_file

Значення: Ці процеси заблоковані в шляхах kernel I/O wait.

Рішення: Зіставте їх з файловими системами/пристроями; не витрачайте час на їх вбивство.

Завдання 3: Подивіться, яке монтування повільне, торкнувшись метаданих

cr0x@server:~$ sudo timeout 3s stat /var/lib/postgresql || echo "stat timed out"
stat timed out

Значення: Навіть операція з метаданими блокується. Це вказує на блокування на рівні файлової системи для цього монтування.

Рішення: Ідентифікуйте блочний пристрій, який підтримує це монтування.

Завдання 4: Зіставте монтування з блочним пристроєм

cr0x@server:~$ findmnt -no SOURCE,TARGET,FSTYPE /var/lib/postgresql
/dev/mapper/mpatha /var/lib/postgresql ext4

Значення: Це пристрій dm-multipath, а не простий /dev/sdX.

Рішення: Перевірте політику multipath і стан шляхів перед зміною налаштувань ext4.

Завдання 5: Шукайте повідомлення ядра про таймаути/скидання

cr0x@server:~$ dmesg -T | egrep -i 'tim(e|ed) out|abort|reset|blk_update_request|I/O error|blocked for more'
[Wed Dec 31 00:01:12 2025] sd 3:0:0:1: timing out command, waited 180s
[Wed Dec 31 00:01:12 2025] blk_update_request: I/O error, dev dm-2, sector 81234567 op 0x1:(WRITE)
[Wed Dec 31 00:03:14 2025] INFO: task jbd2/dm-2-8:123 blocked for more than 120 seconds.

Значення: Ядро чекало 180s перед тим, як оголосити команду таймаутну; потік журналу ext4 заблокований.

Рішення: Ваш бюджет життєздатності витрачається в шарі SCSI/пристрою. Налаштуйте таймаути та/або поведінку multipath.

Завдання 6: Перевірте чергу пристрою та налаштування планувальника

cr0x@server:~$ lsblk -o NAME,TYPE,SIZE,MODEL,HCTL,STATE,SCHED,ROTA
NAME            TYPE  SIZE MODEL            HCTL       STATE SCHED    ROTA
sda             disk  1.8T ST2000NM000A      0:0:0:0    running mq-deadline    1
mpatha          mpath 2.0T                   -          running none           1

Значення: Ротаційне сховище + вибір планувальника впливають на латентність під навантаженням, але це не виправить втрату шляху. Mapper показує none, бо dm-шар відкладає планування.

Рішення: Майте це на увазі пізніше; спочатку стабілізуйте поведінку відмов за допомогою таймаутів.

Завдання 7: Виміряйте латентність і глибину черги

cr0x@server:~$ iostat -x 1 5
Device            r/s   w/s   rkB/s   wkB/s  await  aqu-sz  %util
sda              5.0  85.0    80.0  2400.0  180.0   32.0   99.8
dm-2             0.0  90.0     0.0  2400.0  185.0   31.5   99.9

Значення: await ~180ms з розміром черги ~32 при майже 100% завантаженні. Під відмовою ви можете побачити await у секундах і він може не знижуватися.

Рішення: Якщо це спайк — покращуйте пропускну здатність/чергування. Якщо це стаґ — фокусуйтеся на failover та таймаутах.

Завдання 8: Підтвердіть стан multipath і чи він ставить у чергу

cr0x@server:~$ sudo multipath -ll
mpatha (3600508b400105e210000900000490000) dm-2 HP,MSA2040
size=2.0T features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='service-time 0' prio=1 status=active
| `- 3:0:0:1 sdb 8:16 active ready running
`-+- policy='service-time 0' prio=1 status=enabled
  `- 4:0:0:1 sdc 8:32 failed faulty running

Значення: queue_if_no_path увімкнено; один шлях не працює. Якщо всі шляхи впадуть, I/O буде поставлено в чергу замість повернення помилки.

Рішення: Вирішіть, чи ваш робочий навантаження надає перевагу поставленим у чергу записам (ризик блокування аплікації) або швидкій відмові (ризик помилок запису, але краща життєздатність сервісу).

Завдання 9: Перевірте таймаути dm-multipath (fast fail та device loss)

cr0x@server:~$ sudo cat /sys/block/dm-2/dm/uuid
mpath-3600508b400105e210000900000490000

cr0x@server:~$ sudo cat /sys/block/dm-2/queue/io_timeout
0

Значення: io_timeout 0 зазвичай означає «використовувати за замовчуванням / явного таймауту немає», що часто рівнозначно «чекати довго в іншому місці».

Рішення: Віддавайте перевагу явним політикам: встановіть multipath fast fail і переконайтеся, що SCSI таймаути не абсурдні для ваших SLA.

Завдання 10: Перевірте SCSI таймаут пристрою, що діє

cr0x@server:~$ sudo cat /sys/block/sdb/device/timeout
180

Значення: 180 секунд на команду — це ціле життя у запитах. Одна застрягла команда може приклеїти чергу.

Рішення: Для багатьох середовищ 30–60 секунд — більш розумний максимум, але лише якщо ваше сховище реально може відновитися в цьому вікні.

Завдання 11: Ідентифікуйте транспорт (SAS/iSCSI/NVMe), щоб вибрати правильні ручки

cr0x@server:~$ lsblk -S -o NAME,TRAN,TYPE,MODEL,SERIAL
NAME TRAN TYPE MODEL            SERIAL
sdb  sas  disk HP LOGICAL VOLUME 600508b4...
sdc  sas  disk HP LOGICAL VOLUME 600508b4...

Значення: Це SAS-підтримане сховище, ймовірно через RAID-контролер або SAN-шасі, а не NVMe.

Рішення: В цьому випадку налаштування таймаутів SCSI і політики multipath важать більше, ніж налаштування скидання контролера NVMe.

Завдання 12: Перевірте проблеми на рівні файлової системи (помилки ext4, журнал, remount)

cr0x@server:~$ sudo dmesg -T | egrep -i 'ext4|jbd2|remount|buffer i/o error' | tail -n 20
[Wed Dec 31 00:03:14 2025] INFO: task jbd2/dm-2-8:123 blocked for more than 120 seconds.
[Wed Dec 31 00:03:18 2025] EXT4-fs (dm-2): Delayed block allocation failed for inode 262145 at logical offset 0 with max blocks 16 with error 5

Значення: ext4 бачить I/O помилки і потік журналу заблокований. Операції файлової системи будуть доміноефектом.

Рішення: Виправте підлеглий I/O шлях спочатку. Налаштування файлової системи не перехитрить відсутні блоки.

Завдання 13: Подивіться таймаути systemd і поведінку stop-job (життєздатність сервісів)

cr0x@server:~$ systemctl show postgresql --property=TimeoutStartUSec,TimeoutStopUSec,KillMode
TimeoutStartUSec=1min 30s
TimeoutStopUSec=1min 30s
KillMode=control-group

Значення: systemd чекатиме 90 секунд перед оголошенням невдачі старту/зупинки. Але якщо процес у стані D, він може ігнорувати сигнали завершення.

Рішення: Ви не можете «systemd-ом» вирішити kernel I/O wait. Але ви можете зберегти фронтові сервіси життєздатними, ізолювавши залежні від сховища юніти.

Завдання 14: Підтвердіть, чи ядро засипає попередженням про блоковані задачі

cr0x@server:~$ sudo sysctl kernel.hung_task_timeout_secs
kernel.hung_task_timeout_secs = 120

Значення: Це контроль шуму діагностики, а не фікс. Зміна впливає на час отримання попереджень, а не на повернення I/O.

Рішення: Не «виправляйте» інцидент, заглушивши сигнал тривоги. Використовуйте його для кореляції часу затримок із проблемами шляху.

Завдання 15: Захопіть швидкий стек трейсів заблокованих задач

cr0x@server:~$ echo w | sudo tee /proc/sysrq-trigger
w

Значення: Ядро виведе стеки заблокованих задач у dmesg/journal. Це неприємно, але показує, який шар чекає (dm, scsi, filesystem тощо).

Рішення: Використайте це, щоб довести, чи ви застрягли в чергуванні multipath, SCSI EH чи в очікуванні журналу файлової системи.

Завдання 16: Слідкуйте за атрибутами udev для постійної конфігурації таймауту

cr0x@server:~$ udevadm info --query=all --name=/dev/sdb | egrep 'ID_MODEL=|ID_SERIAL=|ID_WWN=|DEVPATH='
E: DEVPATH=/devices/pci0000:00/0000:00:1f.2/host3/target3:0:0/3:0:0:1/block/sdb
E: ID_MODEL=LOGICAL_VOLUME
E: ID_SERIAL=600508b400105e210000900000490000
E: ID_WWN=0x600508b400105e210000900000490000

Значення: Ви можете зіставити конкретні пристрої (WWN) для застосування udev-прав, які встановлюють таймаути послідовно при перезавантаженні.

Рішення: Якщо ви налаштовуєте таймаути, зробіть їх персистентними через udev або конфіг multipath — а не ручними записами в sysfs щоразу.

Так, це багато команд. Але на он-колі — не час «просто перезавантажити». Перезавантаження підходить; невизначеність дорого коштує.

Налаштування таймаутів, що запобігають повним стагам

Поговоримо про налаштування, що визначають, чи повільний диск викличе «деякі помилки» або «весь вузол перестає відповідати». Правильний вибір залежить від того, чи сховище локальне, RAID, SAN multipath, iSCSI або NVMe. Але форма проблеми однакова: обмежте, скільки ви чекаєте, перш ніж відмовитися, і звіртеся, щоб failover відбувався в цьому межі.

1) Таймаут команди диска SCSI: /sys/block/sdX/device/timeout

Для SCSI-пристроїв (що включає більшість SAS, FC, iSCSI та SAN LUN) кожен блочний пристрій показує таймаут у секундах.

cr0x@server:~$ sudo cat /sys/block/sdb/device/timeout
180

Що він робить: скільки ядро чекає на команду перед оголошенням таймауту і входом у обробку помилок (EH). EH може включати повтори, скидання та відновлення шини.

Чому це викликає стаґи: якщо ви дозволяєте одній команді сидіти 180 секунд, усе, що за нею, може накопичитися. Деякі пристрої/шляхи серіалізують певні команди; ви отримуєте head-of-line blocking.

Що робити: оберіть значення довше за транзитні джитери, але коротше за «ми втратили контроль». Для багатьох корпоративних SAN середнім максимумом є 30–60 секунд. Для ненадійних SATA чи SMR-дисків під навантаженням може знадобитися більше — хоча це сигнал, що ви придбали не той диск.

cr0x@server:~$ echo 60 | sudo tee /sys/block/sdb/device/timeout
60

Операційне рішення: якщо зниження призводить до помилок при нормальному навантаженні, ваше сховище не відповідає очікуванням. Не «вирішуйте» підняттям таймаутів; виправте шлях або навантаження.

2) Зробіть налаштування персистентними через udev-правила

Записи в sysfs зникають при перезавантаженні та перепрояві пристрою. Використайте udev-правила, щоб встановлювати таймаути за WWN/серіалом/моделлю.

cr0x@server:~$ sudo tee /etc/udev/rules.d/60-scsi-timeout.rules >/dev/null <<'EOF'
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd[a-z]*", ENV{ID_WWN}=="0x600508b400105e210000900000490000", ATTR{device/timeout}="60"
EOF
cr0x@server:~$ sudo udevadm control --reload-rules
cr0x@server:~$ sudo udevadm trigger --subsystem-match=block --action=change

Значення: майбутні додавання/зміни застосують таймаут автоматично.

Рішення: робіть це лише після того, як доведете, що новий таймаут не ламає легітимну відновлюваність.

3) dm-multipath: припиніть ставити в чергу вічно, коли шляхи відсутні

Multipath — класичний прискорювач «зависання диска під навантаженням». Якщо всі шляхи падають і ви ставите I/O у чергу, додатки блокуються. Вони не помиляються, не повторюють розумно, вони просто сидять. Це може бути прийнятним для деяких стеків сховища; для stateless сервісів — отрута.

Ключова концепція: чергування ховає відмову. Схована відмова стає вузол-ґлобальною зупинкою.

Подивіться на поточні фічі:

cr0x@server:~$ sudo multipath -ll | sed -n '1,4p'
mpatha (3600508b400105e210000900000490000) dm-2 HP,MSA2040
size=2.0T features='1 queue_if_no_path' hwhandler='0' wp=rw

Що змінити: У багатьох продакшн-середовищах ви хочете швидкої відмови, коли всі шляхи недоступні, плюс обмежене вікно повторних спроб.

  • Вимкніть безкінечне чергування (уникайте queue_if_no_path, якщо немає відчутної причини).
  • Використовуйте fast_io_fail_tmo, щоб швидко віддавати помилку, коли шляхи відсутні.
  • Використовуйте dev_loss_tmo, щоб визначити, скільки часу намагатися відновити шлях перед тим, як здатися.

Приклад фрагменту конфігурації multipath (ідея; адаптуйте до свого середовища):

cr0x@server:~$ sudo tee /etc/multipath.conf >/dev/null <<'EOF'
defaults {
    find_multipaths yes
    user_friendly_names yes
    flush_on_last_del yes
}

devices {
    device {
        vendor "HP"
        product "MSA"
        no_path_retry 12
        fast_io_fail_tmo 5
        dev_loss_tmo 30
        features "0"
    }
}
EOF
cr0x@server:~$ sudo systemctl restart multipathd

Значення: із fast_io_fail_tmo 5 I/O може швидко повернути помилку, якщо шляхів немає (після 5 секунд). Із dev_loss_tmo 30 шляхи вважаються втраченими після 30 секунд.

Рішення: Якщо ваші відновлення fabric займають 20–25 секунд, dev_loss_tmo 30 може працювати. Якщо це займає 2 хвилини — ви або неправильно налаштовані, або живете небезпечно, і таймаути повинні відображати реальність.

Короткий жарт: чергування multipath — як покласти скарги клієнтів у шухлядку «пізніше». Зрештою шухлядки скінчаться.

4) Особливості iSCSI: відновлення сесії vs життєздатність аплікації

Якщо ваші LUN приходять через iSCSI, у вас є додаткові таймаути: TCP-переспроби, заміна сесії iSCSI та multipath. iSCSI може бути дуже надійним, але лише якщо ви виберете операційний підхід: швидка відмова або «тримати записи, поки світ не вилікується».

Перевірте статус сесії:

cr0x@server:~$ sudo iscsiadm -m session
tcp: [1] 10.10.10.20:3260,1 iqn.2001-04.com.example:storage.lun1 (non-flash)

Значення: у вас є активна iSCSI-сесія. Якщо зависання сховища корелюють із падіннями/штормом перепідключень сесії, налаштуйте iSCSI і multipath разом.

Рішення: Не ставте multipath, щоб відмовлятись за 5 секунд, якщо iSCSI потребує 30 секунд для відновлення і ви дійсно хочете пережити це.

5) NVMe: скидання контролера швидке, але не чарівне

На локальному NVMe стаґи зазвичай інші: глюки прошивки, події PCIe AER, термічне дроселювання або проблеми керування живленням. Ви не отримуєте SCSI-таймаутів; ви отримуєте поведінку контролера NVMe та логіку скидання драйвера.

Перевірте помилки NVMe та скидання:

cr0x@server:~$ sudo dmesg -T | egrep -i 'nvme|AER|reset|timeout' | tail -n 20
[Wed Dec 31 00:02:01 2025] nvme nvme0: I/O 123 QID 6 timeout, aborting
[Wed Dec 31 00:02:02 2025] nvme nvme0: reset controller

Значення: драйвер активно абортує й скидає. Це загалом краще, ніж чекати 180 секунд, але скидання все ще може прилипати до файлової системи, якщо відбуваються часто.

Рішення: Якщо скидання часті — спочатку розглядайте це як апаратну/прошивочну проблему. Налаштування таймаутів не замінить стабільний пристрій.

6) Файлова система і опції монтування: не плутайте симптоми з причинами

При справжніх зупинках пристрою опції файлової системи вторинні. Проте деякі вибори впливають на те, як швидко аплікації відчують біль:

  • інтервал commit ext4 впливає, як часто метадані примушуються на диск. Менший commit збільшує тиск синку; більший — збільшує вікно відновлення й спайки латентності.
  • barriers / write cache переважно правильно обробляються сучасними стеками, але неправильно заявлений кеш або вимкнені flush-и можуть перетворити затримки в корупцію.
  • noatime зменшує записи метаданих; це не вирішить зависання, але може зменшити фоновий тиск.

Думка: не намагайтеся «mount-option» вирішити відмову шляху. Виправте шлях, потім оптимізуйте.

7) Таймаути на рівні сервісів: обмежте радіус ураження

Ви не завжди можете запобігти відключенню сховища, особливо мережевого. Ви можете запобігти його захопленню всього вузла, проєктуючи часткову відмовостійкість:

  • Тримайте критичні сервіси поза сумнівними монтуваннями (так, навіть якщо це «тільки логи»).
  • Використовуйте systemd TimeoutStopSec і політики Restart відповідно, але пам’ятайте, що процеси в стані D не можна коректно вбити сигналами.
  • Переважайте таймаути на рівні аплікації. Якщо виклик до бази даних блокується вічно, уся його нитка пулу стає музейним експонатом.

Три міні-історії з корпоративної практики

1) Інцидент через хибне припущення: «SAN переключиться миттєво»

Середня компанія мігрувала набори stateful сервісів на новий масив SAN. Команда зберігання пообіцяла резервні шляхи та «автоматичний failover». Платформна команда почула «миттєво». Це було неправильне слово.

Вузли Linux були налаштовані з dm-multipath і, бо хтось читав best-practices з епохи, коли втрата запису була ворогом, пристрої мали queue_if_no_path. Припущення було: якщо шлях впаде, multipath переступить і апка не помітить. Вони думали як інженери зберігання. Аплікація поводилася як аплікація: вона заблокувалась.

Під час продовженого вікна обслуговування перезавантажився топ-оф-реєк комутатор. Обидва активні шляхи зникли на короткий час — не достатньо, щоб SAN запанікував, але достатньо, щоб вузли Linux поставили в чергу гору записів. Процеси бази даних перейшли в стан D. API-тьєр, що чекав на відповіді БД, заповнив власні черги. Балансувальники бачили «здоровий TCP», але запити таймаутилися в клієнта. Здавалося аплікаційне падіння. Насправді це була відмова життєздатності сховища.

Виправлення було нудним і політично незручним: узгодити RTO для втрати шляху зберігання, а потім налаштувати multipath так, щоб відмовляти I/O у межах цього вікна замість безкінечного чергування. Також додали таймаути нагорі, аби користувацькі запити не чекали застряглого ядра вічно. Наступне перезавантаження комутатора викликало помилки, а не повний стаґ — і система відновилася швидше, бо відмова була видимою й обмеженою.

2) Оптимізація, що обернулась проти: «Збільшити глибину черги для підвищення пропускної здатності»

Аналітична команда мала нічний батч, що навантажував RAID. Доброзичливе підвищення глибини черги дозволило більше одночасних I/O. Показники пропускної здатності покращилися в бенчмарку. Команда святкувала і пішла на обід. Класика.

При реальному навантаженні глибші черги посилили хвостову латентність. Коли масив почав внутрішнє прибирання (garbage collection, parity checks або як там прошивка назвала свою середньожиттєву кризу), окремі I/O стали повільними. З глибокою чергою повільні операції накопичилися. Коли система зауважила, вже було сотні запитів у черзі, і несуміжні процеси почали блокуватися на операціях з метаданими. Вузол не був «повільним». Він був періодично не відповідаючим.

Вони намагалися «вирішити» це підвищенням SCSI таймаутів, щоб ядро не помилялося. Це зменшило видимі помилки, але збільшило тривалість стаґів. Батч тривав довше, бізнес-дашборди відставали, і on-call команда почала розвивати специфічні думки про аналітику.

Відновлення було контрінтуїтивне: зменшити глибину черги, прийняти трохи нижчий піковий пропуск, і отримати передбачувану латентність. Також перенесли обслуговування масиву поза вікна батчів. Система припинила «добре 50 хвилин, мертва 5» — найгірший вид театру надійності.

3) Сумна, але правильна практика, що врятувала день: «Зробіть таймаути явними і тестуйте failover»

Фінансова організація працювала з вузлами Ubuntu і multipath LUN для маленького критичного кластера. Нічого гламурного — просто стабільний I/O, суворі SLA і культура, що не довіряє героїчним порятункам.

Їхня проста практика: таймаути були конфігурацією, а не усною традицією. Для кожного класу сховища вони документували очікуваний час failover і ставили fast_io_fail_tmo, dev_loss_tmo і SCSI device/timeout відповідно. Щоквартально вони проводили вправу: відключити один шлях, потім коротко відключити всі шляхи, і перевірити, що сервіси або швидко відмовляють, або переживають — залежно від контракту сервісу.

Одного дня вищестоящий fabric дав нестабільні відключення шляхів. На вузлах без цієї дисципліни це була б тиха чергова катастрофа. Тут же multipath швидко віддавав помилки настільки, що логіка повторів аплікації спрацювала. Помилки підскочили, але кластер залишився живим. Оператори мали на що реагувати і час, щоб перенацілити трафік.

Постмортем був приємно нудним. Ніякої таємниці. Ніякого «ядро зависло». Просто відомий режим відмови поводився у відомих межах. Саме цього ви й прагнете: нудна система з фінансовими звітами.

Поширені помилки (симптом → причина → виправлення)

1) Симптом: SSH працює, але ls у каталозі зависає

Причина: каталог знаходиться на файловій системі, чий підлеглий блочний пристрій заблокований; запити метаданих чекають завершення I/O.

Виправлення: ідентифікуйте монтування за допомогою findmnt, потім перевірте логи ядра і таймаути пристрою. Якщо multipath — перевірте чергування і втрату шляхів. Якщо локальний диск — перевірте скидання контролера й апаратні логи.

2) Симптом: load average величезний, CPU в основному вільний

Причина: багато задач заблоковані в I/O wait (стан D), що враховується в load average.

Виправлення: використайте ps з wchan, iostat -x і sysrq w для дампів стеків. Цільтеся в шар сховища, а не в планувальник CPU.

3) Симптом: systemd не може зупинити сервіс; stop job висить вічно

Причина: процеси в переривному сні; сигнали не завершать їх, поки ядро чекає на I/O.

Виправлення: виправте I/O шлях. Для локалізації розгляньте ізоляцію монтування, failover або перезавантаження вузла, якщо відновлення неможливе. Не витрачайте годину на налаштування режимів вбивства systemd.

4) Симптом: немає помилок, лише довгі стаґи під час SAN-подій

Причина: multipath ставить I/O у чергу при зникненні шляхів (queue_if_no_path), ховаючи відмову від аплікацій.

Виправлення: відключіть безкінечне чергування і встановіть fast_io_fail_tmo/dev_loss_tmo у обмежені значення, узгоджені з поведінкою відновлення fabric.

5) Симптом: час від часу «EXT4-fs error», далі remount read-only

Причина: підлеглий пристрій повертає I/O помилки або таймаути; файлова система переводить себе в read-only для захисту.

Виправлення: ставтесь до сховища як до ненадійного. Перевірте кабелі, логи HBA, стан масиву, SMART/NVMe логи. Не «виправляйте» mount-опціями.

6) Симптом: налаштування таймаутів «вирішило» зависання, але тепер з’явилися випадкові I/O помилки

Причина: ви зменшили таймаути нижче за час, який потрібно сховищу для відновлення; тепер повільні операції трактуються як помилки.

Виправлення: виміряйте реальний час відновлення/переключення і встановіть таймаути трохи вище за нього. Якщо відновлення занадто повільне — виправте шлях замість того, щоб ховати проблему.

7) Симптом: усе зависає під час ротації логів або бекапів

Причина: синхронний тиск на метадані (fsync-шторм) або насичення одного пристрою записами; журнальна конкуренція блокує несуміжні операції.

Виправлення: обмежте швидкість бекапів, перемістіть логи з критичного тома, використовуйте ionice, зменшіть паралелізм і перевірте, чи пристрій не входить у внутрішнє GC або SMR-падіння записів.

8) Симптом: віртуальна машина зависає, хост виглядає нормально

Причина: чергування на гіпервізорі або бекенд сховища; гість бачить блокований I/O, але метрики хоста це приховують.

Виправлення: вимірюйте на кожному шарі: гостьовий iostat, статистику блоку хоста, латентність масиву. Узгодьте таймаути end-to-end; не дозволяйте гостю чекати довше, ніж хост реально може відновити.

Чеклісти / покроковий план

Покроково: стабілізувати вузол, що «зависає» під дисковим навантаженням

  1. Підтвердьте, що це сховище: перевірте mpstat на iowait і ps на процеси в D-state.
  2. Зіставте біль: використайте findmnt, щоб зіставити уражені каталоги з пристроями.
  3. Прочитайте історію ядра: dmesg на предмет таймаутів, скидань, відмов шляхів і повідомлень файлової системи.
  4. Визначте клас: локальний диск vs multipath SAN vs iSCSI vs NVMe. Не застосовуйте поради для SAN до NVMe і навпаки.
  5. Виміряйте латентність і черги: iostat -x, щоб зрозуміти, чи ви насичені, чи падаєте.
  6. Перевірте політику multipath: шукайте queue_if_no_path і стан шляхів; підтвердьте очікування часу переключення.
  7. Встановіть обмежену поведінку відмови: налаштуйте multipath fast_io_fail_tmo/dev_loss_tmo і SCSI таймаути на основі виміряного часу відновлення.
  8. Зробіть це персистентним: udev-правила для SCSI timeout; /etc/multipath.conf для політик dm.
  9. Обмежте радіус ураження: переконайтесь, що критичні сервіси мають адекватні таймаути запитів; перемістіть некритичні записи (логи, tmp) з критичного монтування.
  10. Тест: симулюйте втрату шляху в контрольованому вікні. Якщо ви не тестували failover — ви керуєте теорією.

Чекліст: значення для вибору (орієнтири, не догма)

  • Спочатку виміряйте: скільки реально триває переключення шляху в вашому середовищі? Використайте це як базу.
  • SCSI device/timeout: часто 30–60s для SAN LUN у стабільних fabric; довше лише якщо масив цього вимагає (але спитайте навіщо).
  • Multipath fast_io_fail_tmo: 5–15s якщо ви віддаєте перевагу швидкій помилці; довше якщо потрібно пережити.
  • Multipath dev_loss_tmo: 30–120s залежно від очікувань відновлення шляхів.
  • Уникайте безкінечного чергування якщо лише ваш стек явно не спроєктований на це.

Чекліст: чого уникати

  • Не «вирішуйте» стаґи шляхом бездумного збільшення таймаутів. Ви можете лише подовжити тривалість відключень.
  • Не відключайте механізми безпеки (flushes/barriers) заради бенчмарків.
  • Не припускайте, що переключення сховища миттєве. Воно рідко таким є, і часто непослідовне.
  • Не ігноруйте процеси в стані D. Вони — ядро, що махає червоною стрічкою, а не баг аплікації.

Питання й відповіді

1) Чому kill -9 не завершує застряглий процес?

Тому що він у переривному сні (стан D), чекаючи на завершення kernel I/O. Ядро не запланує обробку сигналу, поки I/O не повернеться або не відбудеться помилка.

2) Чи kernel.hung_task_timeout_secs — це реальний таймаут, що вирішує зависання?

Ні. Він контролює, коли ядро попередить вас про заблоковані задачі. Це корисно для кореляції, але не для усунення проблеми.

3) Чи слід вимкнути queue_if_no_path у multipath?

У багатьох продакшн-настройках: так, якщо немає задокументованої причини для безкінечного чергування (і плану, як аплікація поводиться під блокуванням). Надавайте перевагу обмеженій відмові з явними вікнами повторів.

4) Яке розумне значення таймауту SCSI?

Розумне — «трохи вище за доведений час відновлення вашого сховища». На практиці багато SAN середовищ опираються на 30–60s; деякі вимагають більше. Якщо вам потрібні 180s — спитайте, які сценарії цього вимагають і чи ваші сервіси це витримають.

5) Якщо я зменшу таймаути, чи втрату дані?

Зменшення таймаутів може перетворити довгі очікування в I/O помилки. Чи це загрожує даними — залежить від аплікації і файлової системи. Бази даних зазвичай віддають перевагу явним помилкам над безкінечним чеканням, але потрібно переконатися, що стек коректно обробляє помилки запису.

6) Моя система «зависає» лише під час бекапів. Це проблема таймаутів?

Часто це насичення і чергування, а не відмова шляху. Перевірте iostat -x на 100% util і високий await. Тоді зменшіть паралелізм бекапу, застосуйте ionice або перемістіть бекап на менш критичний шлях.

7) Як зрозуміти, чи це диск, контролер чи SAN?

Почніть з dmesg. Скидання контролера, помилки лінку і відмови шляхів залишають відбитки. Потім корелюйте з multipath -ll (шляхи), таймаутами пристрою і метриками латентності (iostat). Якщо mapper показує всі шляхи вниз і ставить у чергу — це не вина ext4.

8) Чи змінює налаштування планувальника I/O проблему стаґів?

Планувальники можуть покращити справедливість і латентність під навантаженням, особливо на ротаційних дисках. Вони не виправлять відсутній шлях або пристрій, що перестав відповідати. Розглядайте налаштування планувальника як фазу два.

9) Чи перезавантажувати вузол із багатьма процесами в стані D?

Якщо сховище не відновлюється і вузол фактично заблокований — так, перезавантаження може бути найшвидшим шляхом відновити сервіс. Але вам ще потрібно виправити поведінку таймаутів/фейловера, інакше перезавантаження повториться.

10) Чи можуть systemd таймаути захистити від дискових стаґів?

Вони захищають від сервісів, що зависають у просторовому просторі користувача. Вони не надійно захищають від kernel I/O wait. Використовуйте їх для гігієни, а не як стратегію надійності сховища.

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

Якщо машини Ubuntu 24.04 «зависають» під дисковим навантаженням, ядро зазвичай робить саме те, що ви йому наказали: чекати. Ваше завдання — явно встановити очікування щодо того, скільки чекати дозволено, перш ніж відновлення або відмова повинні спрацювати.

  1. Пройдіть швидкий план діагностики на одному ураженому вузлі і збережіть dmesg, iostat -x, multipath -ll і дамп blocked-task через sysrq.
  2. Оберіть бюджет життєздатності (в секундах, не в хвилинах) для втрати шляху і узгодьте таймаути SCSI та налаштування multipath з ним.
  3. Зробіть ці налаштування персистентними через udev-правила і /etc/multipath.conf.
  4. Протестуйте відмову: відключіть один шлях, потім коротко всі шляхи в контрольованому вікні. Переконайтесь, що поведінка відповідає тому, що ваші сервіси можуть терпіти.
  5. Лише після стабілізації життєздатності — оптимізуйте продуктивність: глибина черги, планувальник і формування навантаження.

Кінцевий стан, який ви хочете, — не «немає помилок». Це «помилки трапляються швидко, передбачувано і відновлювано», не перетворюючи ваш вузол на дуже дорогий додаток для медитації.

← Попередня
ZFS canmount: налаштування, що запобігає сюрпризам при завантаженні
Наступна →
Рівні попадань кешу ZFS: коли вони важливі, а коли — ні

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