Ubuntu 24.04: зависання диска під навантаженням — таймаути, що запобігають повним простоям (Випадок №30)

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

Зазвичай усе починається однаково: затримки зростають, приладові панелі жовтіють, і ваш «швидкий» сервіс перетворюється на музейний експонат. SSH-сеанси зависають під час команди. База даних перестає відповідати. CPU без справи, RAM у порядку, мережа виглядає нормально — і все одно машина відчувається так, ніби застрягла в мокрому цементі.

На Ubuntu 24.04 найобурливіший варіант цього — «зависання» диска під навантаженням: не чистий збій і не очевидний креш, а загальносистемний простій, бо I/O на сховище не завершується, а таймаути занадто довгі (або відсутні там, де це важливо). Виправлення рідко зводиться до «купіть швидший диск». Частіше — «змусити систему швидко віддавати помилку, ізолювати збитки і не дозволити одному заблокованому пристрою тримати весь хост у заручниках».

Що насправді означає «зависання диска» (і чому хост замерзає)

Коли люди кажуть «диск завис», вони часто мають на увазі одне з трьох:

  1. Пристрій або шлях перестає завершувати I/O. Ядро чекає, повторює спроби і чекає ще. Додатки блокуються в невідмінювальному сні (D стан). Якщо достатня кількість критичних потоків заблокована, хост виглядає замороженим.
  2. I/O завершується, але настільки повільно, що це не відрізняється від зависання. Глибина черг вибухає, затримка з мілісекунд переходить у хвилини, і все, що потребує збереження, фактично недоступне.
  3. Один шар стеку зберігання сериалізує обробку помилок. Один мертвий шлях тримає блокування, одна черга застрягає, один контролер переходить у цикл скидання, і решта системи шикується за ним.

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

Є причина, чому це боляче: диск I/O — залежність практично для всього. Логи, стан, тимчасові файли, менеджери пакетів, DNS-кеші, накопичувачі метрик, шари контейнерів — проблеми зі сховищем ламають не лише базу даних. Вони руйнують вашу здатність спостерігати за збоєм.

Одна перефразована ідея, що часто приписується Вернеру Фогелсу (reliability engineering): Усе ламається, тож проектуйте під відмови, а не робіть вигляд, ніби їх не буде. Таймаути для сховища — саме про це: вирішувати, як ви будете віддавати помилку.

Дві незручні істини:

  • Жодна окрема настройка таймауту не «виправляє» зависання. Потрібні узгоджені таймаути по шарах, щоб відновлення відбувалося в передбачуваний проміжок.
  • Занадто агресивні таймаути можуть спричинити власні відмови — особливо на зайнятих масивах, перевантажених обсягах у хмарі або ненадійних multipath-сценах.

Жарт №1: Сховище ніколи не «вимикається», воно просто заглиблюється в медитацію над непостійністю пакетів.

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

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

Перше: підтвердьте, що це сховище, і знайдіть «жертву» пристрій

  • Перевірте логи ядра на наявність таймаутів/скидів. Якщо ви бачите SCSI timeouts, NVMe controller resets або «blocked for more than … seconds», ви на правильній статті.
  • Перелічіть заблоковані задачі та скупчення в D-стані. Якщо багато потоків у D стані, це майже завжди I/O очікування на пристрій або журнал файлової системи.
  • Співвіднесіть точки монтування → пристрої. Якщо /var або монтування бази даних знаходиться на проблемному пристрої, весь хост почуватиметься гірше, ніж коли це просто холодне дане.

Друге: визначте, чи це на рівні пристрою, шляху чи навантаження

  • Рівень пристрою? Журнали SMART/NVMe, помилки носія, скидання лінку, скидання контролера.
  • Рівень шляху? Втрата сесії iSCSI, флапи FC-лінку, failover multipath-шляхів, повідомлення «no path».
  • Рівень навантаження? Один процес робить шалені sync-записи, зависання журналу файлової системи, writeback-конгешн, насичення глибини черги.

Третє: оберіть найменш погане пом’якшення

  • Якщо шлях мертвий і налаштований multipath: налаштуйте перевірку шляхів і таймаути відмови так, щоб відмова відбулася швидко.
  • Якщо пристрій застряг: плануйте видалення/ізоляцію. На одно-дисковому хості це часто перезавантаження. На надлишковому стеку (RAID, multipath, кластерна FS) зазвичай можна ізолювати.
  • Якщо це насичення навантаженням: зменшіть конкуренцію, відрегулюйте queue depth/scheduler або виправте навантаження (буферизація, батчинг, асинхронні операції).

Цікаві факти та історичний контекст

  • Раніше Linux за замовчуванням використовував CFQ для планування I/O для справедливості на обертових дисках; сучасні ядра віддають перевагу mq-deadline або none через багаточергову блокову підсистему.
  • Таймаути SCSI походять з епохи повільних пристроїв, коли очікування 30–60 секунд не було дивним; для сучасних сервісів це вічність.
  • Попередження «hung task» існують, бо невідмінювальний сон — це можливість, а не баг. Ядро навмисне не завжди може безпечно вбити задачу, що чекає на I/O.
  • Multipath створювався для ненадійних шляхів, а не для неконсистентного мислення. Він може гарно приховувати транзитні збої — поки таймаути не розходяться і це не блокує вашу SLA.
  • NVMe змінив модель відмов. Воно настільки швидке, що стара логіка «просто повторити спробу деякий час» може стати катастрофічною при тиску черги.
  • Writeback-конґешн — стара проблема (VM і блоковий шар борються з нею десятиліттями), але вона все ще кусає, коли співпадають брудні пороги і журналювання.
  • EXT4 і XFS оптимізовані насамперед для цілісності. Застряглий журнал/лог може зробити весь монтувальний пункт «мертвим», навіть якщо інша частина пристрою «в порядку».
  • Хмарне блочне сховище принесло нові патології латентності. Троттлінг, «голосні сусіди» і бекендове обслуговування можуть виглядати як «випадкові зависання» в гостьовій ОС.

Механіка: таймаути за рівнями (блок, SCSI, NVMe, multipath, файлові системи)

Щоб зупинити повні простої, потрібно зрозуміти, хто за кого чекає. Стек зберігання — це ланцюг обіцянок:

  • Додаток обіцяє, що може блокуватися на I/O.
  • Файлова система обіцяє впорядкування і відновлення (журнал/лог).
  • Блоковий шар обіцяє ставити в чергу і відправляти I/O.
  • Драйвер пристрою обіцяє спілкуватися з апаратурою і відновлюватися після помилок.
  • Транспорт (SATA/SAS/NVMe/FC/iSCSI) обіцяє доставку — або принаймні помилку.

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

Таймаути на блоці (request timeouts)

В блоці Linux існує концепт request timeout. Для багатьох пристроїв це представлено як:

  • /sys/block/<dev>/device/timeout (поширено для SCSI)
  • /sys/class/block/<dev>/queue/ параметри (глибина черги, планувальник тощо)

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

SCSI: таймаути команд і обробка помилок

SCSI має явні таймаути команд (історично 30 секунд — поширений приклад). На локальному SAS-диску це може бути прийнятно. На SAN з multipath і великими кешами це може бути занадто коротко (помилкові таймаути). На нестабільному шляху це може бути занадто довго (затримка failover).

Обробка помилок SCSI також може блокувати. Якщо пристрій у поганому стані, ви можете бачити повторювані спроби скидання в dmesg. Хитрість — узгодити таймаути SCSI з multipath і відновленням транспорту, щоб один шар брав відповідальність за failover або швидке віддавання помилки — а не всі одразу змагалися між собою.

NVMe: таймаути контролера і цикли скидання

NVMe зазвичай «або летить, або горить». Коли воно ламається, зазвичай це відбувається скиданням контролера. Ви побачите повідомлення про таймаути і скидання. Основна ручка — таймаут ядра NVMe і поведінка при втраті контролера (залежить від kernel/driver). Деякі налаштування — параметри модуля; інші — per-device sysfs.

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

Multipath: де «висока доступність» стає «високою тривожністю»

Device-mapper multipath може або врятувати, або загальмувати вас. Найбільша причина відмов — неузгоджені таймаути:

  • Таймаут команди SCSI занадто довгий.
  • Перевірка шляху multipath повільно оголошує шлях мертвим.
  • Поведінка черг налаштована на «queue forever», коли шляхів немає.

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

Файлові системи: зависання журналу/лога виглядає як зависання пристрою

EXT4 використовує журнал; XFS — лог. Якщо критичні операції запису метаданих не можуть завершитись, файлова система може блокувати виклики. Навіть якщо базовий блок-пристрій «частково в порядку», монтувальний пункт може відчуватися повністю застряглим, бо операції з метаданими сериалізуються.

Також: fsync() патерни можуть змусити ваше сховище виглядати завислим. Один процес, що робить синхронні записи в щільному циклі, може домінувати над затримками для всіх. Якщо ви коли-небудь бачили «чому система зависла?» і відповідь була «хтось включив синхронне логування скрізь», — вітаю в клубі.

Жарт №2: Диск не повільний — він просто бенчмаркує ваше терпіння.

Практичні завдання: 12+ команд, як читати вивід, яке рішення приймати

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

Завдання 1: Перевірити підписи таймаутів I/O в логах ядра

cr0x@server:~$ sudo dmesg -T | egrep -i 'timed out|timeout|reset|I/O error|blk_update_request|hung task|blocked for more than' | tail -n 40
[Mon Dec 30 10:11:02 2025] sd 2:0:0:0: timing out command, waited 30s
[Mon Dec 30 10:11:02 2025] blk_update_request: I/O error, dev sdb, sector 12345678 op 0x1:(WRITE) flags 0x0 phys_seg 8 prio class 0
[Mon Dec 30 10:11:05 2025] scsi host2: sas: attempt task abort!
[Mon Dec 30 10:11:22 2025] INFO: task postgres:2211 blocked for more than 120 seconds.

Значення: У вас є реальний пристрій/рівень драйвера в стресі, а не просто «БД працює повільно». Наявність timing out command і спроб скасування/скиду свідчить, що ядро намагається відновитись.

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

Завдання 2: Швидко ідентифікувати скупчення в D-стані

cr0x@server:~$ ps -eo state,pid,comm,wchan:32 --sort=state | head -n 20
S     1 systemd         ep_poll
D  2211 postgres        io_schedule
D  2450 postgres        xfs_log_force_lsn
D  3102 rsyslogd        blk_mq_get_tag
R  4021 ps              -

Значення: Кілька процесів у D стані, що чекають у I/O-пов’язаних функціях ядра. xfs_log_force_lsn — явний маркер тиску/зависання лога XFS.

Рішення: Смійтеся у бік файлової системи і перевірок пристрою. Якщо заблоковані процеси — критичні демони (journald, rsyslog, база даних), хост почуватиметься «завислим».

Завдання 3: Побачити в реальному часі латентність I/O і глибину черги за допомогою iostat

cr0x@server:~$ iostat -x 1 5
Linux 6.8.0-xx-generic (server)  12/30/2025  _x86_64_  (16 CPU)

Device            r/s   w/s  rkB/s  wkB/s  await  svctm  %util
sda              5.0  12.0   120.0  900.0    2.1    0.3    3.0
sdb            200.0  80.0 25600.0  6400.0 1800.0    1.2  100.0
dm-2           195.0  75.0 25000.0  6000.0 1850.0    1.1  100.0

Значення: await у секундах при %util на максимумі означає, що пристрій насичений або завис. dm-пристрій відповідає поведінці базового диска, що вказує на вузьке місце нижче файлової системи.

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

Завдання 4: Співвіднести монтування з пристроями (знати, що ви збираєтесь зламати)

cr0x@server:~$ lsblk -f
NAME        FSTYPE FSVER LABEL UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1      ext4   1.0         2b4a...                               120G    20%   /
└─sda2      swap   1           9f31...
sdb
└─mpatha    LVM2_member       3JkQ...
  ├─vg0-data xfs                8d1c...                                80G    85%   /var/lib/postgresql
  └─vg0-log  xfs                7a2b...                                10G    40%   /var/log

Значення: Проблемний диск sdb підтримує LVM-томи з даними PostgreSQL і логами. Це пояснює системний біль.

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

Завдання 5: Підтвердити, чи використовується multipath і інспектувати його поведінку

cr0x@server:~$ sudo multipath -ll
mpatha (3600508b400105e210000900000490000) dm-2 LIO-ORG ,TCMU device
size=200G features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='service-time 0' prio=50 status=active
| `- 2:0:0:0 sdb 8:16  active ready running
`-+- policy='service-time 0' prio=10 status=enabled
  `- 3:0:0:0 sdc 8:32  active ready running

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

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

Завдання 6: Перевірити SCSI таймаут для пристрою

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

Значення: SCSI-команди тайм-аутяться через 30 секунд (поширений дефолт). Це на команду, а повторні спроби/скиди можуть значно розширити загальний час простою.

Рішення: Якщо вам потрібен швидший failover (multipath), можна зменшити це — обережно. Якщо у вас повільний SAN, який іноді зависає, можливо, потрібно збільшити, але тоді переконайтесь, що інші шари не ставлять I/O у чергу назавжди.

Завдання 7: Переглянути налаштування черги і планувальника (продуктивність vs латентність)

cr0x@server:~$ cat /sys/block/sdb/queue/scheduler
[mq-deadline] kyber bfq none

Значення: Активний mq-deadline. Це часто добрий дефолт для блокових пристроїв, яким корисна обмежена латентність. Для NVMe також поширено none.

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

Завдання 8: Перевірити, чи таймаути відбуваються на блоці

cr0x@server:~$ sudo journalctl -k -b | egrep -i 'blk_update_request|Buffer I/O error|reset|timed out' | tail -n 30
Dec 30 10:11:02 server kernel: blk_update_request: I/O error, dev sdb, sector 12345678 op 0x1:(WRITE) flags 0x0 phys_seg 8 prio class 0
Dec 30 10:11:05 server kernel: sd 2:0:0:0: timing out command, waited 30s
Dec 30 10:11:06 server kernel: scsi host2: sas: attempt task abort!

Значення: Підтверджує, що ядро видає помилки і вказує пристрій та тип операції (READ/WRITE).

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

Завдання 9: Знайти процес, який насідає на диск

cr0x@server:~$ sudo iotop -oPa
Total DISK READ: 25.00 M/s | Total DISK WRITE: 8.00 M/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN  IO>    COMMAND
 2211 be/4 postgres    18.00 M/s   4.00 M/s  0.00 % 98.00 % postgres: checkpointer
 2305 be/4 postgres     6.00 M/s   2.50 M/s  0.00 % 65.00 % postgres: walwriter

Значення: База даних — головний споживач I/O і витрачає багато часу на очікування I/O (великий IO% у стовпчику).

Рішення: Якщо пристрій хворий, вбивати процес не допоможе; він просто перемістить очікування. Якщо це перевантаження — налаштуйте checkpointing / WAL і конкуренцію сховища.

Завдання 10: Перевірити журнал помилок NVMe і скидання контролера (якщо NVMe)

cr0x@server:~$ sudo nvme list
Node             SN                   Model                                    Namespace Usage                      Format           FW Rev
/dev/nvme0n1     S4G8...              ACME NVMe 3.2TB                           1         1.20  TB /   3.20  TB    512   B +  0 B   1.2.3

cr0x@server:~$ sudo nvme smart-log /dev/nvme0
critical_warning                    : 0x00
temperature                         : 44 C
available_spare                     : 100%
percentage_used                     : 3%
media_errors                        : 0
num_err_log_entries                 : 12

cr0x@server:~$ sudo nvme error-log /dev/nvme0 | head -n 10
Entry[0]
  error_count     : 12
  sqid            : 3
  cmdid           : 0x0042
  status_field    : 0x4004
  parm_err_loc    : 0x0000

Значення: Є помилки (num_err_log_entries). Не всі помилки NVMe фатальні, але вони сильно корелюють зі штурмовими скиданнями і стрибками латентності.

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

Завдання 11: Підтвердити логіку multipathd і події перевірки шляхів

cr0x@server:~$ sudo journalctl -u multipathd -b | tail -n 40
Dec 30 10:10:51 server multipathd[812]: sdb: tur checker reports path is down
Dec 30 10:10:55 server multipathd[812]: mpatha: remaining active paths: 1
Dec 30 10:11:15 server multipathd[812]: sdb: reinstated

Значення: Шляхи флапають. Якщо failover/встановлення триває занадто довго, хост застрягає, поки multipath вирішує, яка реальність правильна.

Рішення: Налаштуйте інтервали перевірки multipath і політику повторних спроб, щоб вони відповідали вашому бюджету толерантності для пауз.

Завдання 12: Перевірити сигнали здоров’я файлової системи (приклад XFS)

cr0x@server:~$ sudo dmesg -T | egrep -i 'xfs|ext4|journal|metadata' | tail -n 30
[Mon Dec 30 10:11:01 2025] XFS (dm-2): log I/O error -5
[Mon Dec 30 10:11:01 2025] XFS (dm-2): metadata I/O error: block 0x12a3f error 5

Значення: Файлова система бачить I/O помилки. Це вже не «може бути повільно». Це збій.

Рішення: Зупиніть записи, якщо можливо (failover сервісів), збережіть логи і плануйте відновлення/ремонт. Не продовжуйте бити по проблемному лог-пристрою.

Завдання 13: Перевірити тиск writeback (dirty ratios), що може імітувати зависання

cr0x@server:~$ sysctl vm.dirty_background_ratio vm.dirty_ratio vm.dirty_expire_centisecs vm.dirty_writeback_centisecs
vm.dirty_background_ratio = 10
vm.dirty_ratio = 20
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500

Значення: Це розумні дефолти. На дуже швидких операціях запису у повільні диски, ліміти dirty можуть перевищуватися, спричиняючи блокування потоків у writeback — ще один вигляд «зависання».

Рішення: Якщо бачите застої без повідомлень про помилки пристрою і з великою кількістю dirty-сторінок — обережно налаштуйте ці параметри і виправте буферизацію навантаження.

Завдання 14: Швидко заміряти розподіл латентності за допомогою fio (режим безпечного тесту)

cr0x@server:~$ sudo fio --name=latcheck --filename=/var/lib/postgresql/.fio-testfile --size=256M --rw=randread --bs=4k --iodepth=16 --numjobs=1 --direct=1 --time_based --runtime=20 --group_reporting
latcheck: (groupid=0, jobs=1): err= 0: pid=5123: Mon Dec 30 10:20:01 2025
  read: IOPS=18.2k, BW=71.2MiB/s (74.7MB/s)(1.39GiB/20001msec)
   lat (usec): min=70, max=540000, avg=880, stdev=12000

Значення: Максимальна латентність 540ms (або гірше) під час випадкових читань свідчить про серйозну «tail latency». Якщо максимум у секундах/хвилинах — ви в зоні зависань.

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

Параметри таймаутів, що запобігають повним простоям (що налаштовувати і як)

Говоримо чесно: найбезпечніше «ніколи не буде простою» налаштування — «ніколи не робити I/O». Оскільки це неможливо, реальна мета така:

  • Виявляти відмову достатньо швидко, щоб переключитись на резерв (якщо є) або помітно визнати відмову ноди (якщо ні).
  • Запобігати безкінечному ставленню I/O у чергу, що перетворює один поганий диск/шлях на повний простій хосту.
  • Тримати таймаути узгодженими, щоб один шар не чекав 5 хвилин, поки інший очікує відновлення за 10 секунд.

1) Multipath: припиніть чергування назавжди (обмежений біль)

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

Чому «queue_if_no_path» небезпечний: Він чудово поводиться при короткочасних блиманнях шляху. Він катастрофічний, коли фабрика зв’язку впала, ціль зникла або зламалася аутентифікація. Ваші процеси блокуються, чекаючи I/O, який ставиться в порожнечу.

Рекомендації для продакшну:

  • Для кластерів із переміщенням на рівні ноди (Kubernetes, Pacemaker тощо) віддавайте перевагу обмеженому чергуванню, щоб нода падавала і сервіс переселявся.
  • Для однохостових, нерезервних систем, де чекати краще, ніж відмовляти (рідко), чергування може бути прийнятним — але ви свідомо обираєте простої ноди.

Приклад концепції конфігурації multipath (не посилання, лише ручки):

  • no_path_retry: скільки разів пробувати при відсутності шляхів; може бути числовим або fail.
  • dev_loss_tmo і налаштування транспорту: як довго ядро зберігає пристрій після втрати зв’язку (поширено для iSCSI/FC).
  • fast_io_fail_tmo: як швидко віддавати помилку I/O при падінні шляхів (залежить від FC/iSCSI).
  • polling_interval: з якою частотою multipath перевіряє шляхи.

На Ubuntu 24.04 multipath зазвичай конфігурується через /etc/multipath.conf. Ви хочете узгодити:

  • Час виявлення шляху (checker + polling) з
  • Тим, скільки додатки можуть чекати (таймаути сервісів, таймаути БД) і
  • Скільки ядро повторює SCSI команди перед оголошенням пристрою мертвим.

Правило великого пальця: якщо ваш оркестратор вбиває/замінює ноду за 60 секунд, не налаштовуйте сховище так, щоб воно ставило в чергу на 10 хвилин «про всяк випадок». Ви отримаєте лише повільний збій.

2) SCSI таймаут пристрою: налаштовуйте обачно (і ніколи поодинці)

Tаймаути SCSI — на команду. Система може повторювати і скидувати кілька разів. Зменшення таймауту може пришвидшити failover, але може також спричинити непотрібні скидання при транзитних затримках.

Коли зменшення таймаутів SCSI допомагає:

  • На мультипат-фабриках, де один шлях мертвий і потрібен швидкий failover.
  • На хостах, де «зависання на хвилини» гірше за «швидка помилка I/O».
  • У середовищах, де бекенд надійний і таймаут дійсно означає відмову.

Коли зменшення ризиковане:

  • На зайнятих SAN, які інколи підвисають на десятки секунд під час обслуговування.
  • При навантаженнях з великими I/O на повільних носіях, де тривалі операції очікувані.
  • На контролерах з довгою поведінкою відновлення (деякі RAID HBA).

На практиці ви налаштовуєте SCSI таймаути разом з no-path поведінкою multipath і таймерами транспорту. Інакше отримаєте класичну проблему: ядро продовжує повторювати, а multipath продовжує чергувати.

3) Таймаути транспорту (iSCSI/FC): зробіть відмову явною

Багато «зависань диска» на SAN-backed томах — фактично збої транспорту. Для iSCSI сесійні/транспортні таймаути визначають, як швидко виявляється втрата сесії і як швидко I/O повертає помилку ОС. Для FC існують подібні концепції через fast I/O fail таймери і device loss таймери.

Чому це важливо: якщо ОС думає, що пристрій все ще існує, вона чекатиме. Якщо вона однозначно скаже «пристрій зник», multipath зможе переключитись або система впаде чисто.

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

4) NVMe таймаути: уникайте штормів скидання

Для NVMe занадто короткі таймаути можуть спричинити багаторазові скидання контролера під час піків латентності. Шторми скидання — особливий вид біди, бо «дія відновлення» стає причиною відмови.

Що робити замість сліпого зменшення таймаутів:

  • Вимірюйте хвостову латентність під реалістичним навантаженням (Завдання 14).
  • Перевіряйте проблеми прошивки і журнали помилок (Завдання 10).
  • Валідуйте стабільність PCIe лінку (логи ядра часто показують AER-помилки під час проблем).

5) Файлова система і таймаути додатків: не уявляйте, що диск безсмертний

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

  • Драйверах баз даних і пулах підключень
  • RPC-клієнтах
  • systemd watchdog (де це доречно)
  • Перевірках здоров’я кластера і механізмах fencing

Правильна філософія: відмови сховища повинні робити ноду хворою швидко і явно, а не повільно і моторошно.

Три корпоративні історії з реальних випадків

Інцидент через неправильне припущення: «Multipath = немає відмов»

Вони запускали набір API-серверів на Ubuntu. Сховище було на SAN, multipath ввімкнений, і всі спали спокійно, бо було «два шляхи». Під час середньотижневого зміни в комутаторній підсистемі одна фабрика почала випадково скидати кадри.

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

Зовні API виглядали напівживими. Деякі запити зависали. Інші успішно проходили. Балансувальники навантаження продовжували посилати трафік, бо TCP ще працював, а health checks були надто поверхневі. На хостах процеси накопичувались у D-стані. Перезапуск сервісів не допоміг; скрипти перезапуску теж потребували дискового I/O.

Виправлення не було героїчним. Вони змінили multipath, щоб припинити чергування назавжди, підсилили таймінги перевірки шляхів і — це те, що часто пропускають — зробили health checks додатків перевірками запис/читання на критичних монтуваннях. Після цього реальна відмова сховища викликала швидку деградацію ноди, її дренаж і припинення плутанини.

Оптимізація, що призвела до провалу: «Надемо глибину черги і iodepth на максимум»

Розгін продуктивності цілеспрямовано торкнувся pipeline пакетного прийому. Команда збільшила конкуренцію скрізь: більше воркерів, більше з’єднань з БД, більші I/O depth у інструментах. На тихому сховищі бенчмарки виглядали чудово.

Потім у продакшні нагрянув сплеск трафіку під час бекендового обслуговування сховища. Латентність зросла, черги заповнилися, і ті вищі глибини стали самонанесеним DoS. Система витрачала більше часу на керування чергами, ніж на корисну роботу. Хвостова латентність пішла вертикально вгору.

Гірше, їхні таймаути залишалися дефолтними. Тож замість швидкого віддавання помилки і маршрутизації задач хост зависав у довгих циклах повторів. Моніторинг бачив «хост увімкнений», але сервіс практично мертвий. Операторам довелося жорстко перезавантажувати ноди, щоб відновити планувальну здатність.

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

Нудна, але правильна практика, що врятувала ситуацію: «Бюджет таймаутів і регулярні тренування відмов»

Інша організація мала змішаний флот: деякі локальні NVMe, деякі SAN, деякі хмарні томи. У них була політика: для кожного класу сховища повинен бути задокументований бюджет таймаутів: скільки ОС може чекати, скільки multipath може чергувати, як швидко оркестратор фенсить.

Це не було розкішно. Документ — таблиця. Її переглядали щоквартально. Команда також виконувала контрольовані «витягни шлях» тренування на staging SAN і імітувала деградований хмарний том під навантаженням у тестах.

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

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

Типові помилки: симптом → корінь → виправлення

1) Симптом: хост «замерзає», але CPU низький

Корінь: процеси застрягли в невідмінювальному сні (D-стан) чекаючи I/O; часто заблокований журнал/лог файлової системи.

Виправлення: визначте пристрій/монтування (Завдання 2–4), перевірте логи ядра (Завдання 1) і припиніть безкінечне чергування в multipath, якщо це застосовно.

2) Симптом: пристрій multipath існує, але I/O зависає на хвилини при блиманнях SAN

Корінь: queue_if_no_path або надто вільний no_path_retry з повільною перевіркою шляхів.

Виправлення: налаштуйте обмежену політику повторів/відмов і узгодьте інтервали перевірки шляхів із бюджетом таймаутів сервісів (Завдання 5, Завдання 11).

3) Симптом: повторювані «resetting controller» повідомлення (NVMe або HBA)

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

Виправлення: перевірте прошивку/журнали здоров’я (Завдання 10), подивіться лічильники помилок і не скорочуйте таймаути, поки не зрозумієте хвостову латентність.

4) Симптом: «blocked for more than 120 seconds» з’являється, потім зникає, потім повертається

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

Виправлення: корелюйте з логами multipath (Завдання 11) та подіями транспорту; налаштуйте failover і зменшіть конкуренцію навантаження, щоб контролювати накопичення черг.

5) Симптом: I/O помилки в dmesg, файлові системи перемонтовуються в readonly

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

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

6) Симптом: «все повільно» під час бекапів або пакетних робіт, без помилок ядра

Корінь: насичення глибини черги і writeback-конґешн; іноді неправильно підібраний I/O scheduler для типу пристрою.

Виправлення: обмежте конкуренцію, розплануйте важкі роботи, розгляньте налаштування планувальника після тестування (Завдання 7) і обережно відрегулюйте writeback-параметри (Завдання 13).

7) Симптом: зависає лише один монтувальний пункт, решта системи в порядку

Корінь: локальний лог/журнал файлової системи на конкретному пристрої або LVM LV; інші монтування на інших пристроях не зачеплені.

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

Контрольні списки / покроковий план

Покроково: під час активного інциденту «зависання під навантаженням»

  1. Захопіть швидкі докази: фрагменти логів ядра (Завдання 1), докази заблокованих задач (Завдання 2) і iostat (Завдання 3). Збережіть їх де-небудь поза хостом, якщо можливо.
  2. Оцініть вплив: визначте, яке монтування/пристрій задіяно (Завдання 4). Якщо це /, /var або монтування БД, очікуйте широкого радіуса ураження.
  3. Визначте надлишковість: чи використовуєте ви multipath/RAID/кластер? Якщо так — зазвичай можна ізолювати поганий шлях/пристрій. Якщо ні — плануйте контрольоване перезавантаження і заміну.
  4. Якщо multipath: підтвердьте, чи стоїть у вас черга назавжди (Завдання 5). Якщо так — вирішіть, чи переключитись на обмежену поведінку як частину плану фіксу.
  5. Перевірте реальні I/O помилки: journalctl логи ядра (Завдання 8) і повідомлення файлової системи (Завдання 12).
  6. Перевірте драйвери навантаження: iotop (Завдання 9), щоб побачити, чи є один винуватець або загальний тиск.
  7. Мітігація: failover сервісів, дренування ноди або fencing/reboot. Не продовжуйте перезапускати додатки, що заблоковані на I/O.
  8. Після відновлення: виконайте контрольоване вимірювання латентності (Завдання 14), щоб перевірити, чи хвостова латентність знову адекватна.

Покроково: безпечне впровадження налаштувань таймаутів (план змін)

  1. Визначте бюджет таймаутів (приклад: «нода може застопоритись на сховищі не довше 30 секунд, перш ніж вважатися нездоровою»). Без цього ви налаштовуєте наосліп.
  2. Перерахуйте типи сховищ: локальні SATA/SAS, NVMe, iSCSI/FC SAN, хмарні томи, dm-crypt, LVM, RAID, multipath.
  3. Зафіксуйте поточні налаштування: SCSI таймаути, конфіг multipath, таймаути транспорту, планувальник, queue depth.
  4. Вирішіть поведінку при відмові: віддаєте перевагу швидкій помилці I/O або чеканню? Більшість розподілених систем повинні віддавати помилку швидко.
  5. Узгодьте шари:
    • Транспорт виявляє втрату шляху в межах бюджету.
    • Multipath переключається або віддає помилку I/O в межах бюджету.
    • SCSI/NVMe таймаути не перевищують бюджету на порядок величини.
  6. Тестуйте за допомогою ін’єкції відмов: відключіть шлях, вимкніть ціль, обмежте пропускну здатність тома, потім спостерігайте тривалість зависання і поведінку додатків.
  7. Впроваджуйте поступово: одне середовище, один клас сховища за раз.
  8. Моніторте хвостову латентність і рівень помилок під час rollout; відкатуйте зміни, якщо спричинили шторм скидань або помилкові відмови.

Саніті чек: як виглядає «добре»

  • Один мертвий шлях швидко викликає failover multipath і видно в логах.
  • Немає безкінечного чергування на критичних монтуваннях, якщо ви явно цього не обрали.
  • Додатки мутть таймаути і повтори на рівні додатка замість вічного зависання.
  • Перевірки здоров’я ноди ловлять недоступність сховища (не лише «процес існує»).
  • Хвостова латентність залишається обмеженою під піковим навантаженням, а не лише середня латентність.

Поширені питання (FAQ)

1) Це проблема Ubuntu 24.04 чи Linux загалом?

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

2) Чому один поганий диск робить весь хост ніби замороженим?

Тому що критичні процеси блокуються на I/O. Якщо journald, rsyslog, сервіси пакетів або ваша база даних заблоковані в D-стані, усе — від логіну до моніторингу — може стояти за ними.

3) Мені просто зменшити всі таймаути до 1 секунди?

Ні. Ви створите помилкові відмови і шторм скидань, особливо на SAN і NVMe під навантаженням. Встановлюйте таймаути на основі виміряної хвостової латентності і бюджету відмов вашого сервісу.

4) Який найнебезпечніший параметр multipath?

queue_if_no_path без обмеженої політики повторів. Він може перетворити «немає доступних шляхів» у «хост виглядає мертвим», що дуже погано для користувачів.

5) Як відрізнити насичення навантаженням від відмови пристрою?

Насичення зазвичай проявляється високим %util і зростаючою латентністю без помилок ядра. Відмови пристрою показують таймаути, скиди і I/O помилки в логах ядра (Завдання 1 і Завдання 8).

6) Чи можуть файлові системи викликати зависання, навіть якщо диск в порядку?

Вони можуть посилювати проблему. Навантаження, яке змушує часті синхронні коміти журналу, може затримати монтування під тиском. Але справді «здоровий диск» із катастрофічними проблемами файлової системи трапляється рідше, ніж хочеться вірити.

7) Мій хмарний том іноді ставить паузу на 20–60 секунд. Чи треба збільшити таймаути?

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

8) Чому вбивство заблокованого процесу не вирішує зависання?

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

9) Який найбезпечніший спосіб тестувати налаштування таймаутів?

Ін’єкція відмов у staging: свідомо відключіть шлях, вимкніть ціль або обмежте том під репрезентативним навантаженням. Заміряйте тривалість зависання і поведінку відновлення, потім налаштовуйте.

10) Коли перезавантаження — правильна відповідь?

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

Висновок: наступні кроки, які можна зробити сьогодні

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

  1. Під час наступної події, збирайте три важливі артефакти: рядки таймаутів з dmesg, докази процесів в D-стані і вивід iostat -x (Завдання 1–3).
  2. Співвіднесіть монтування з пристроями, щоб знати, що саме застрягає (Завдання 4). Домислювання витрачає години.
  3. Якщо ви використовуєте multipath, перевірте, чи не ставите ви I/O в чергу назавжди, і вирішіть, чи це відповідає вашим цілям доступності (Завдання 5). Більшість сучасних платформ віддають перевагу обмеженому провалу.
  4. Напишіть бюджет таймаутів для вашого класу сховища і узгодьте SCSI/NVMe/транспорт/multipath поведінку з ним. Якщо ви не можете сказати «ми віддаємо помилку I/O приблизно за N секунд», ви не контролюєте свої відмови.
  5. Проведіть контрольоване тренування відмов і спостерігайте, чи ваша нода падає швидко або повільно застрягає. Потім налаштовуйте на основі даних, а не містики.

Зависання диска не завжди можна повністю запобігти. Повні простої хосту — зазвичай можна. Змушуйте систему обирати чітку відмову, швидко, і ваше життя on-call одразу покращиться — навіть якщо життя постачальника сховища залишиться… збагачувальним досвідом.

← Попередня
MySQL vs Percona Server: безпечніші налаштування — менше тонкого налаштування, менше простоїв
Наступна →
Пекло принтерів: індустрія, яку всі однаково ненавидять

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