Proxmox: припиніть «випадкові» зависання віртуальних машин, виправивши один параметр ядра хосту

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

«Випадкові» зависання віртуальних машин на Proxmox мають особливий талант: вони трапляються під час тієї єдиної наради, де ви пообіцяли, що платформа «вже стабільна». Гостьова система перестає відповідати, моніторинг мовчить, а потім — за кілька хвилин — ніби нічого й не трапилося, все повертається до роботи. Жодного краху. Жодного перезавантаження. Просто проміжок часу й дедалі менша довіра до гіпервізора.

Здебільшого це не «зачакована» VM. Це затримка запису на хості: ядро Linux дозволяє накопичувати dirty-пам’ять, а потім різко гальмує, коли нарешті мусить виконати flush. Ваші VM відчувають це як зависання, бо потоки QEMU блокуються через I/O на хості та тиск запису в пам’ять. Вирішення нудне, але точне: налаштуйте параметри vm.dirty_* на хості, щоб ядро починало скидати дані раніше й не застосовувало надто жорстку примусову затримку.

Як насправді виглядає «зависання» (і чого це не є)

Люди називають це «випадковим зависанням VM», бо переживають його з боку гостьової ОС: SSH перестає відповідати, RDP зависає, додатки таймаутяться, агенти моніторингу не звітують, а потім все відновлюється без втручання. Але з погляду хоста часто це не випадковість. Це передбачувана пауза, викликана flush-ом накопичених dirty-сторінок, сплеском синхронних записів або тим, що пристрій зберігання раптово «має думку» про затримку.

Класичний шаблон

  • Одна чи кілька VM перестають відповідати на десятки секунд до кількох хвилин.
  • Хост Proxmox «на зв’язку» (ping працює, можливо навіть UI завантажується), але відчувається повільним.
  • iowait підскакує або завантаження CPU виглядає дивно низьким, поки все стоїть.
  • Графіки сховища показують стіну латентності: IOPS падають, латентність зростає.
  • Після паузи все «наздоганяє», у логах видно часовий розрив.

Чого це зазвичай не є

Перед тим як звинувачувати writeback, виключимо типові помилкові напрямки:

  • Це не обов’язково паніка гостьового ядра. Вони лишають очевидні сліди.
  • Це не завжди бракує оперативної пам’яті. Тиск по RAM може сприяти, але тут симптом — це хост, що примушує записи.
  • Це не завжди «ZFS повільний». ZFS може посилити проблему, якщо маються sync-записи або поведінка slog, але механізм пауз може статися і на ext4, XFS, Ceph тощо.
  • Це не (тільки) CPU steal. Steal час шкодить, але багатомінутне зависання з мінімальним використанням CPU зазвичай свідчить про I/O-тормоз і накопичення writeback.

Цинічна правда така: ваша VM — це процес, і Linux охоче ставитиме цей процес на паузу, щоб захистити цілісність сховища і не потонути в dirty-даних. Ядро не зле — воно послідовне.

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

Одна сім’я параметрів ядра, що зазвичай вирішує проблему: vm.dirty_*

Якщо вам потрібен один важіль, що зупиняє багато «випадкових» зависань VM на Proxmox — це ось він: зменшити обсяг dirty-пам’яті, який хосту дозволено накопичувати перед початком writeback і перед примусовим гальмуванням.

Linux використовує RAM як буфер запису. Коли процес пише у файл, він часто пише у page cache спочатку (dirty-сторінки). Пізніше ядро скидає ці сторінки на диск («writeback»). Зазвичай це підвищує продуктивність. Але якщо система дозволяє dirty-сторінкам накопичуватися занадто багато, остаточний flush може стати насильницькою подією: бурі writeback, насичення черги пристрою та throttling, що блокує процеси — в тому числі й ваші QEMU/KVM гостьові ОС.

Ручки, що мають значення

  • vm.dirty_background_ratio / vm.dirty_background_bytes: коли включається фонова writeback.
  • vm.dirty_ratio / vm.dirty_bytes: коли foreground-процеси отримують throttling, щоб примусити writeback.
  • vm.dirty_expire_centisecs: як довго dirty-дані можуть лежати, перш ніж вважатися застарілими і мають бути скинуті.
  • vm.dirty_writeback_centisecs: як часто потоки flusher прокидаються для запису dirty-даних.

Типова пастка на Proxmox — це те, що за замовчуванням значення у відсотках масштабуються від RAM. Велика RAM у хоста? Великий dirty-буфер. Великий dirty-буфер + повільне або сплескове сховище? Зрештою — writeback-затримка, що здатна зависнути VM.

Чому це здається проблемою VM

Бо віртуальний диск VM живе на хостовому сховищі, а I/O-потоки QEMU — це просто потоки хоста. Коли ядро хоста вирішує «ми зараз будемо писати, а всі інші зачекають», гості чекають теж. Ваш додаток бачить паузу. SRE отримує пейджер. Фінансовий директор питає «чому ми платимо за це?»

Цитата, яку варто повісити у кімнаті, бо вона болісно практична:

«Надія — не стратегія.» — James Cameron

Коли ви керуєте гіпервізорами, «надіятись, що ядро робитиме flush м’яко» — це саме надія без плану.

Чому Proxmox робить цю проблему помітною

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

Множення піків

На одиночному bare-metal сервері writeback-буря — це «додаток повільний». На гіпервізорі — це «пів компанії повільне». Ви агрегуєте I/O-патерни: бази даних з fsync, шіпери логів, оновлення Windows, завдання бекапу, шари контейнерів і випадкові бенчмарки розробників, яким «потрібні цифри».

Стек сховища може посилити паузи

Деякі поширені налаштування хороші, але вони також можуть зробити паузу катастрофічною:

  • ZFS з синхронними навантаженнями: Якщо гості виконують багато синхронних записів (бази даних, журналювання, Windows), латентність може виглядати як зависання.
  • Ceph під відновленням/backfill: Варіабельність латентності — норма, і writeback може вдарити у найгірший момент.
  • Потребительські SSD з поведінкою SLC-кешу: Вони бігають швидко, потім йдуть пішки, потім повзуть. Ваш page cache вірить у спринт.
  • RAID-контролери з політиками кешу: Кеш запису без батарейного захисту — це практично латентна пастка.

Коли ви поєднуєте «великий RAM-буфер» + «реальність бурстів», хост врешті вимагає дисципліни. Саме ця вимога сприймається як зависання.

Швидка діагностика: план дій (першочергові кроки)

Якщо у вас є тільки 10 хвилин між «щось зависло» і «це відновилося», робіть це в зазначеному порядку. Ви не збираєтеся марні дані — ви вирішуєте, чи це writeback/I/O, тиск по пам’яті або щось інше.

Перший крок: підтвердити, що це I/O + writeback, а не краш гостя

  • Перегляньте логи хоста на наявність заблокованих задач і повідомлень про writeback.
  • Перевірте, чи була high-значення dirty-пам’ять і чи потім вона впала.
  • Перевірте латентність сховища на хості у вікні події.

Другий крок: ідентифікуйте, що наситилося (диск, контролер, мережеве сховище)

  • Запустіть iostat і подивіться на %util і латентність.
  • Перевірте черги по пристроям; один проблемний пристрій може заморозити все, якщо він утримує журнал/пул.
  • Підтвердіть, чи ви на ZFS, Ceph, LVM-thin або файлових образах. «Правильний» наступний крок відрізняється.

Третій крок: перевірте тиск по пам’яті та поведінку swap

  • Подивіться на MemAvailable, swap in/out і чи хост активно виконує reclaim.
  • Підтвердіть, що ballooning або KSM не створюють додаткової турбулентності.

Якщо докази вказують на writeback-затори, припиніть дебати і налаштуйте vm.dirty_*. Ви все одно можете шукати робоче навантаження, яке це спричинило, але спочатку потрібно, щоб платформа не зупинялася.

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

Це реальні, виконувані перевірки на хості Proxmox (Debian-based). Кожне завдання містить: команду, що означає її вивід, і яке рішення прийняти далі. Запускайте їх під root або з sudo.

Завдання 1: Визначте версію Proxmox і ядра (контекст має значення)

cr0x@server:~$ pveversion -v
proxmox-ve: 8.1.0 (running kernel: 6.5.13-5-pve)
pve-manager: 8.1.3
pve-kernel-6.5: 6.5.13-5

Що це означає: Поведінка ядра і значення за замовчуванням відрізняються між версіями. Знати, чи ви на PVE-ядрі і яка серія — корисно для пояснення поведінки writeback і blk-mq.

Рішення: Якщо у вас старіша серія ядра і ви бачите баги з blocked task, що вже виправлені upstream, заплануйте оновлення ядра після стабілізації налаштувань.

Завдання 2: Перевірте поточні налаштування dirty (підозрювані)

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

Що це означає: При 256 GB RAM dirty_ratio=20 може дозволяти ~51 GB dirty-кешу перед примусовим throttling. Це вже не буфер — це стиль життя.

Рішення: На хостах з великою пам’яттю і спільним сховищем віддавайте перевагу *_bytes над ratio або використовуйте значно менші ratio.

Завдання 3: Подивіться, скільки зараз dirty-пам’яті

cr0x@server:~$ egrep -i 'dirty|writeback' /proc/meminfo
Dirty:              124812 kB
Writeback:              0 kB
WritebackTmp:           0 kB

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

Рішення: Якщо Dirty під час інцидентів виростає до гігабайт, ви хороший кандидат для суворіших порогів dirty.

Завдання 4: Шукайте заблоковані задачі і writeback-стали в логах ядра

cr0x@server:~$ journalctl -k -b --no-pager | egrep -i 'blocked|hung|writeback|congestion|task'
[ 2893.441122] INFO: task kvm:23144 blocked for more than 120 seconds.
[ 2893.441126]       Tainted: P           O      6.5.13-5-pve #1
[ 2893.441130] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[ 2893.441133] task:kvm             state:D stack:0     pid:23144 ppid:1 flags:0x00004002
[ 2893.441140] Call Trace:
[ 2893.441150]  __io_schedule+0x2d/0x60
[ 2893.441161]  io_schedule+0x12/0x40
[ 2893.441170]  bit_wait_io+0x11/0x60
[ 2893.441185]  __wait_on_bit+0x4c/0x110

Що це означає: state:D — це uninterruptible sleep, зазвичай I/O wait. Якщо потоки QEMU/KVM з’являються тут, VM «заморожена», бо хост-потік чекає на I/O.

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

Завдання 5: Швидка перевірка латентності та завантаження I/O

cr0x@server:~$ iostat -x 1 5
Linux 6.5.13-5-pve (server) 	02/04/2026 	_x86_64_	(32 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           3.21    0.00    2.11   38.44    0.00   56.24

Device            r/s     w/s   rkB/s   wkB/s  aqu-sz  await  svctm  %util
nvme0n1         12.0   980.0   512.0 65536.0   45.12   46.8   0.9   92.5

Що це означає: Високе %iowait, велике await і високе %util свідчать про насичення пристрою і черги запитів.

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

Завдання 6: Підтвердіть бекенд сховища для дисків VM

cr0x@server:~$ pvesm status
Name             Type     Status           Total            Used       Available        %
local             dir     active        19633960         2341232        16210228   11.92%
local-zfs         zfspool active       191260672        84528128       106732544   44.19%
ceph-vm           rbd     active              0               0               0    0.00%

Що це означає: Знання, чи VM живе на ZFS, Ceph RBD чи в директорії, змінює, куди дивитися далі.

Рішення: Якщо VM на ZFS і зависання корелюють із синхронно-важким навантаженням або scrub’ами, також перевіряйте налаштування ZFS та slog. Якщо на Ceph — перевіряйте стан кластера і backfill.

Завдання 7: Якщо ZFS: перевірте стан пулу та потенційні причини латентності

cr0x@server:~$ zpool status -v
  pool: rpool
 state: ONLINE
config:

	NAME        STATE     READ WRITE CKSUM
	rpool       ONLINE       0     0     0
	  mirror-0  ONLINE       0     0     0
	    nvme0n1 ONLINE       0     0     0
	    nvme1n1 ONLINE       0     0     0

errors: No known data errors

Що це означає: Здоровий пул не гарантує гарну латентність, але хворий пул гарантує погані дні.

Рішення: Якщо ви бачите degraded vdevs або resilvering, очікуйте пауз і відкладіть дискусії про продуктивність до відновлення відмовостійкості.

Завдання 8: Якщо ZFS: перевірте, чи форсуються sync-записи

cr0x@server:~$ zfs get -o name,property,value -s local,default sync rpool
NAME   PROPERTY  VALUE
rpool  sync      standard

Що це означає: sync=standard означає, що ZFS поважає семантику O_SYNC/fsync. Якщо хтось поставив sync=disabled, вони «виправили» латентність ціною безпеки даних.

Рішення: Якщо на сховищі VM вказано sync=disabled, поверніть налаштування, якщо ви не готові пояснювати втрату даних аудиторам.

Завдання 9: Перевірте тиск пам’яті та активність swap

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:           251Gi       182Gi       6.2Gi       2.1Gi        63Gi        54Gi
Swap:           16Gi       3.1Gi        13Gi

Що це означає: Якщо available низький і використання swap швидко зростає під час інцидентів, можливо у вас проблема з пам’яттю, яка погіршує поведінку writeback.

Рішення: Якщо на хості активне свапування, дослідіть ballooning та overcommit. Але не плутайте thrash swap з writeback-затримками — вони можуть співіснувати.

Завдання 10: Зафіксуйте в реальному часі зміни Dirty/Writeback під час паузи

cr0x@server:~$ watch -n 1 'grep -E "Dirty|Writeback" /proc/meminfo; echo; vmstat 1 2 | tail -1'
Every 1.0s: grep -E Dirty|Writeback /proc/meminfo; echo; vmstat 1 2 | tail -1

Dirty:           8421120 kB
Writeback:        412512 kB

 2  0      0 123456 789012 345678    0    0  20480  10240  38  4 56  2  0

Що це означає: Dirty у багатьох ГБ плюс стійкий блок I/O (bi/bo) і високий wa вказують, що система активно скидає дані.

Рішення: Якщо Dirty наростає до «обриву flush», ваші пороги dirty надто ліберальні щодо реалій сховища.

Завдання 11: Перегляньте процеси QEMU для підказок про D-state

cr0x@server:~$ ps -eo pid,stat,comm,args | egrep 'qemu-system|kvm' | head
23144 D    qemu-system-x86 /usr/bin/kvm -id 103 -name vm103 ...
23188 S    qemu-system-x86 /usr/bin/kvm -id 104 -name vm104 ...

Що це означає: D state для QEMU узгоджується з uninterruptible I/O wait. Одна застрягла VM може вказувати на конкретний диск; багато застряглих VM — на спільне насичення сховища.

Рішення: Якщо багато процесів QEMU одночасно в D-state, припиніть звинувачувати гостей. Зосередьтеся на ядровому рівні та шляху зберігання.

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

cr0x@server:~$ for d in nvme0n1 nvme1n1; do echo "== $d =="; cat /sys/block/$d/queue/scheduler; cat /sys/block/$d/queue/nr_requests; done
== nvme0n1 ==
[mq-deadline] kyber none
1024
== nvme1n1 ==
[mq-deadline] kyber none
1024

Що це означає: Сучасні ядра використовують blk-mq. Планувальники важливі менше, ніж раніше, але глибина черги може впливати на латентність під бурстом.

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

Завдання 13: Перевірте, чи ви використовуєте ratio чи bytes (уникати несподіваного масштабування)

cr0x@server:~$ sysctl vm.dirty_bytes vm.dirty_background_bytes
vm.dirty_bytes = 0
vm.dirty_background_bytes = 0

Що це означає: 0 означає, що активні налаштування на основі ratio. На великій RAM ratio можуть бути надто щедрими.

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

Завдання 14: Перевірте, що потоки writeback виконують роботу (і не зависли)

cr0x@server:~$ ps -eo pid,stat,comm | egrep 'flush|writeback|kworker' | head -n 10
  157 S    flush-8:0
  158 S    flush-8:16
  612 S    kworker/u64:3
  948 S    kworker/u64:7

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

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

Завдання 15: Підтвердіть, що зміни відбулись нещодавно (бо завжди хтось щось міняв)

cr0x@server:~$ journalctl --since "24 hours ago" --no-pager | egrep -i 'apt|kernel|zfs|ceph|firmware' | head -n 30
Feb 04 01:12:03 server apt[11902]: upgrade zfsutils-linux:amd64 2.2.2-pve1 to 2.2.3-pve1
Feb 04 01:12:10 server apt[11902]: upgrade pve-kernel-6.5.13-4-pve to 6.5.13-5-pve

Що це означає: Оновлення ядра і стеку сховища можуть змінювати поведінку writeback, значення за замовчуванням і регресії продуктивності.

Рішення: Якщо зависання почалися після оновлення, не відкочуйтеся сліпо. Збирайте докази, налаштуйте writeback, а потім тестуйте регресії контрольовано.

Застосувати виправлення та зробити його персистентним

Спочатку зробіть зміни вживу (щоб спостерігати вплив), потім зафіксуйте їх. Хости Proxmox — це production-системи; поводьтеся відповідно: контроль змін, maintenance-window, план відкату.

Тимчасове застосування (негайний ефект)

cr0x@server:~$ sysctl -w vm.dirty_background_bytes=268435456
vm.dirty_background_bytes = 268435456
cr0x@server:~$ sysctl -w vm.dirty_bytes=1073741824
vm.dirty_bytes = 1073741824
cr0x@server:~$ sysctl -w vm.dirty_writeback_centisecs=100
vm.dirty_writeback_centisecs = 100
cr0x@server:~$ sysctl -w vm.dirty_expire_centisecs=3000
vm.dirty_expire_centisecs = 3000

Що це означає: Хост почне фонового flush при ~256 MB dirty і буде сильніше тримати throttle близько 1 GB dirty, замість десятків GB.

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

Зробити персистентним через перезавантаження

Створіть окремий sysctl drop-in. Не засовуйте це в випадкові файли, які ви забудете за півроку.

cr0x@server:~$ cat > /etc/sysctl.d/99-proxmox-writeback.conf <<'EOF'
# Proxmox host writeback tuning to reduce VM stalls under bursty IO
vm.dirty_background_bytes = 268435456
vm.dirty_bytes = 1073741824
vm.dirty_writeback_centisecs = 100
vm.dirty_expire_centisecs = 3000
EOF
cr0x@server:~$ sysctl --system
* Applying /etc/sysctl.d/99-proxmox-writeback.conf ...
vm.dirty_background_bytes = 268435456
vm.dirty_bytes = 1073741824
vm.dirty_writeback_centisecs = 100
vm.dirty_expire_centisecs = 3000

Що це означає: Налаштування тепер частина конфігурації завантаження.

Рішення: Заносьте цю зміну в ваш infra-repo або систему трекінгу. Майбутнє «ви» заслуговує на підтвердження.

Підтвердіть, що ratio більше не діють

cr0x@server:~$ sysctl vm.dirty_ratio vm.dirty_background_ratio vm.dirty_bytes vm.dirty_background_bytes
vm.dirty_ratio = 20
vm.dirty_background_ratio = 10
vm.dirty_bytes = 1073741824
vm.dirty_background_bytes = 268435456

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

Рішення: Залиште ratio як є, якщо не плануєте уніфікувати конфіги; ефективна поведінка зараз — на основі байтів.

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

1) Симптом: VM зависає на 30–180 секунд, потім відновлюється; хост показує високий iowait

Корінна причина: Накопичення dirty-сторінок приводить до бурі writeback; потоки QEMU блокуються в D-state.

Виправлення: Зменшити пороги dirty (віддати перевагу vm.dirty_background_bytes і vm.dirty_bytes), збільшити частоту writeback (vm.dirty_writeback_centisecs=100), перевірити латентність сховища.

2) Симптом: зависання корелюють з бекапами або вікнами vzdump

Корінна причина: Завдання бекапу створюють write-burst (тимчасові файли, стиснення, активність snapshot), що переповнює page cache і насичує сховище.

Виправлення: Налаштування writeback + чергування бекапів + обмеження I/O бекапів через QoS на рівні сховища, якщо є. Також перевірити латентність цілі бекапу.

3) Симптом: «виправлення» через ZFS sync=disabled, зависання зменшились, але з’явились побоювання щодо цілісності даних

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

Виправлення: Повернути sync=standard. Якщо синхронна латентність реальна, додати SLOG на пристроях з захистом від втрати живлення або перемістити синхронно-важливі навантаження на відповідне сховище.

4) Симптом: лише одна VM зависає, інші в порядку; хост не явно проблемний

Корінна причина: Ця VM інтенсивно навантажує конкретний том або шлях зберігання; може бути один RBD-образ, ZVOL або диск у пулі, що викликає ретраї.

Виправлення: Перевірити латентність по пристроях (iostat -x), статистику по VM-диску і стан сховища. Загальне налаштування dirty допомагає, але ізолюйте «гарячу точку».

5) Симптом: хост залишається чутливим, але годинник гостя «стрибає» і додатки таймаутять

Корінна причина: Потоки vCPU гостя стоять; час відновлюється, коли VM знову запускається.

Виправлення: Той самий базовий підхід: зменшити host writeback-затримки. Також перевірити конфігурацію guest agent/clocksource, якщо дрейф часу стає хронічним.

6) Симптом: зависання з’явилися після «оптимізації продуктивності», що збільшила кеш або RAM

Корінна причина: Більше RAM означає, що ratio дозволяють більше dirty-даних; події flush стають більшими й менш передбачуваними.

Виправлення: Перехід на байтові пороги dirty. Стабільність важливіша за теоретичну пропускну здатність на гіпервізорі.

7) Симптом: VMs на Ceph зависають під час recovery/backfill

Корінна причина: Сплески латентності на бекенді призводять до backlog’у writeback на хості і подальшого throttling.

Виправлення: Налаштування writeback на гіпервізорах плюс тонке налаштування Ceph recovery і наявність запасу потужності. Не чекайте, що гіпервізор «заліпить» насичений кластер.

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

Міні-історія №1: Інцидент через помилкове припущення

Команда щойно оновила вузли Proxmox: більше ядер, більше RAM, та ж сама полиця зберігання. Вони припускали, що оновлення лише покращить ситуацію. І тиждень усе було добре. Потім почалися «випадкові зависання». Не щодня. Не щогодини. Достатньо часто, щоб звинуватити «той старий додаток».

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

Під час одного вікна freeze хост не був вимкнений. Він просто чекав. Логи ядра показали заблоковані потоки QEMU. /proc/meminfo показав Dirty у десятках гігабайтів прямо перед тим, як пауза закінчилася. Більше RAM тихо збільшило розмір dirty-буфера через ratio-based дефолти.

Вони перейшли на байтові пороги dirty і ввели агресивний фон. Зависання припинилися. Пропускна здатність у бенчмарках трохи впала. Нікому це не було важливо, бо платформа перестала «повертати час» у робочі години.

Міні-історія №2: Оптимізація, що відкотилась

Інша організація «розумно» оптимізувала продуктивність. Вони помітили, що сплески латентності сховища корелюють з sync-записами гостей, тому застосували класичне «виправлення»: встановили ZFS sync=disabled для датасету з дисками VM. Графіки одразу стали чудовими. «Зависання» зникли. Квиток закрили з гордим коментарем про «розблокований ZFS».

Два місяці потому відбувся інцидент живлення в рамі. UPS спрацював, більшість вузлів вимкнулися нормально. Один вузол не завершився чисто. Декілька VM повернулися з некоректними базами даних. Не всі — лише стільки, щоб викликати розбір польотів з неприємними питаннями.

Провина не в ZFS. ZFS зробив те, що йому сказали: підтверджувати sync-запити до того, як вони були надійно збережені. Команда обміняла стабільність латентності на гарантії цілісності, а потім здивувалася наслідкам фізики.

Відновлення включало повернення sync у стандарт, додавання пристроїв журналу з захистом від втрати живлення для навантажень, що дійсно потребують sync-продуктивності, і, так — налаштування vm.dirty_*, щоб хост не накопичував величезні flush-кліфи.

Міні-історія №3: Нудна, але правильна практика, що врятувала день

Третя організація керувала кластером Proxmox для внутрішніх сервісів. Нічого гламурного: тикетинг, CI-ранери, кілька Windows VM для ліцензування. Вони робили одну нудну, але постійну річ: мали базовий sysctl-профіль хоста, який застосовувався через управління конфігурацією, включно з writeback-тюнінгом. Кожен вузол на день один виглядав однаково.

Одного кварталу вони додали нове навантаження: pipeline даних, що записував великі послідовні файли і потім робив сплески метаданих. Навантаження було гучним і підвищило використання сховища. Але «випадкових зависань» не було. Пороги dirty запобігли величезним flush-подіям; writeback відбувався безперервно у фоні.

Коли один вузол швидко збудували під розширення, хтось забув застосувати базовий профіль. Той вузол почав заморожувати VM під новим pipeline-навантаженням. Команда не витрачала дні на дебати про виробників сховищ. Вони порівняли sysctl між вузлами, помітили відсутній профіль writeback, застосували його і продовжили роботу.

Це не було героїчно. Це було правильно. Найкращий інцидент — той, на який вас не запрошують.

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

Покроково: стабілізація хоста Proxmox, що зависає в продакшені

  1. Негайно зафіксуйте докази: фрагмент логів ядра з blocked tasks; значення Dirty/Writeback; вивід iostat -x під час паузи.
  2. Підтвердіть бекенд сховища: ZFS vs Ceph vs LVM-thin vs dir images. Не діагностуйте всліпу.
  3. Застосуйте тимчасовий writeback-тюнінг: встановіть байтові пороги dirty і коротший інтервал writeback.
  4. Спостерігайте за одним циклом навантаження: бекапи, batch-завдання або час, який раніше тригерив зависання.
  5. Персистуйте налаштування: sysctl drop-in, управління конфігурацією і запис у систему змін.
  6. Зменшіть бурстовість: чергуйте бекапи, обмежте паралелізм, уникайте одночасного flush всіх VM.
  7. Перевірте запас по латентності сховища: якщо await залишається високим, у вас ще є проблема зі сховищем. Тюнінг запобігає обривам; він не робить повільні диски швидкими.
  8. Післяінцидентний огляд: знайдіть робоче навантаження, що перевантажило систему, і вирішіть: ізолювати, обмежити або перемістити його.

Чекліст: що стандартизувати в кластері Proxmox

  • Байтові пороги dirty (щоб уникнути сюрпризів при різних розмірах RAM).
  • Однакові серії ядра на вузлах (не змішуйте поведінки бездумно).
  • Політика розкладу бекапів (чергування, обмеження паралельності).
  • Моніторинг сховища, орієнтований на латентність, а не лише на пропускну здатність.
  • Документована позиція щодо поведінки ZFS sync (без ad-hoc відключень).
  • Політика swap на хості і політика ballooning.

План відкату (бо ви дорослі люди)

  1. Збережіть копію попередніх sysctl-значень (або експортуйте знімок sysctl -a для підмножини vm.*).
  2. Якщо продуктивність неприпустимо впала — поступово збільшуйте vm.dirty_bytes (наприклад, з 1 GB до 2 GB), а не повертайтеся одразу до ratio.
  3. Якщо хост усе одно зависає, найімовірніше шлях сховища насичений або неправильно працює; шукайте root cause латентності, залишаючись з помірними порогами.

Цікаві факти й історія (бо ядра пам’ятають довго)

  1. Writeback в Linux був постійним полем бою ще від часів 2.4/2.6; баланс throughput vs latency змінюється з апаратурою.
  2. Сторінки «dirty» в кеші існують, бо диск повільний, але вони стають небезпечними, коли диск непередбачувано повільний — наприклад SSD під GC.
  3. Ratio-based дефолти масштабуються з RAM, що мало сенсу, коли сервери мали мало пам’яті; сьогодні це може створювати багатогігабайтні події flush.
  4. Попередження «blocked task» — це спосіб Linux сказати вам: потоки застрягли в uninterruptible sleep, зазвичай чекаючи I/O.
  5. Сучасні ядра використовують blk-mq (multi-queue block layer), що змінює поведінку черг і планувальників порівняно зі старим single-queue.
  6. NVMe зробив throughput дешевим, але не усунув tail latency; саме tail latency викликає зависання VM.
  7. ZFS підкреслює цілісність даних; тюнінг на швидкість шляхом відключення sync-семантики — не безпечний трюк, він змінює коректність.
  8. Віртуалізаційні стеки підсилюють конкуренцію, бо багато навантажень ділять одне ядро по I/O та політикам пам’яті; налаштування хоста важливіше, ніж на одноцільових серверах.
  9. Тюнінг writeback — класичний SRE-хід: ви не оптимізуєте додаток, ви формуєте поведінку системи під навантаження, щоб уникнути каскадних відмов.

Поширені запитання

1) Чи справді vm.dirty_* — це «один параметр»?

Це одна підсистема з кількома ручками. На практиці байтові пороги плюс коротший інтервал writeback — найвпливовіша зміна на боці хоста для цих шаблонів зависань.

2) Чи вирішить це всі зависання Proxmox?

Ні. Це вирішує поширений клас: host writeback-стали і I/O-насичення, що блокують потоки QEMU. Якщо у вас CPU-конкуренція, помилки PCIe, проблеми з прошивкою чи диск помирає — це не вилікує все.

3) Використовувати dirty_ratio чи dirty_bytes?

На гіпервізорах краще dirty_bytes і dirty_background_bytes. Ratio масштабуються з RAM і призводять до непослідовної поведінки на вузлах з різним об’ємом пам’яті.

4) Чи не знизять менші пороги dirty продуктивність?

Іноді так — піковий throughput може трохи впасти, бо ви частіше робите фонові flush. На гіпервізорі це зазвичай корисний компроміс: стабільна латентність краща за випадкові обриви, що заморожують кілька VM.

5) З яких значень починати?

Почніть з dirty_background_bytes=256MB, dirty_bytes=1GB, dirty_writeback_centisecs=100, dirty_expire_centisecs=3000. Потім налаштовуйте за спостереженнями латентності і характеру навантаження.

6) Чи взаємодіє це з ARC ZFS?

Так, опосередковано. ARC і page cache обидва використовують RAM. ARC не є Linux page cache, але динаміка тиску пам’яті все одно впливає на writeback-поведінку. Це налаштування націлене на Linux dirty writeback, а не на ARC.

7) А VMs на Ceph?

Все одно релевантно. Хост все ще кешує і записує. Варіабельність латентності Ceph може викликати більші backlog-и і сильніший throttling. Налаштуйте writeback і переконайтесь, що кластер Ceph має запас потужності та не постійно відновлюється.

8) Чи варто відключити swap на хості Proxmox?

Не відключайте сліпо. Невеликий swap може бути страховкою, але активне свапування в нормі зазвичай вказує на overcommit або проблеми з ballooning. Виправте причину, а не ховайте симптом.

9) Чи можна встановити vm.dirty_writeback_centisecs занадто низько?

Можна. Надто низькі значення збільшать активність фонових флашів і накладні витрати. 100 (1 секунда) — практичний старт для гіпервізорів; вимірюйте й регулюйте за потреби.

10) Як довести, що тюнінг спрацював?

Вимірюйте до/після: частота і тривалість пауз, хвостова латентність iostat await під час піків, поведінка Dirty/Writeback під час вікон бекапів і чи потоки QEMU все ще потрапляють у D-state під час інцидентів.

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

  1. Впровадьте байтові пороги dirty на одному вузлі Proxmox, спостерігайте повний цикл бекапу, потім розгорніть по кластеру.
  2. Додайте скрипт для швидкого захоплення інциденту (навіть простий shell), що записує: iostat -x, лічильники Dirty у /proc/meminfo і релевантні рядки з логів ядра при повідомленнях про зависання.
  3. Аудитуйте політику збереження надійності сховища: якщо хтось «поліпшив» продуктивність через sync=disabled, відкотіть і спроектуйте справжнє рішення (SLOG, розміщення навантаження або апгрейд сховища).
  4. Заплануйте бурстові завдання (бекапи, scrub-и, реплікацію) так, щоб вони не падали одночасно, як синхронізоване шоу.
  5. Встановіть очікування всередині організації: гіпервізори — це системи, орієнтовані на латентність. Оптимізуйте під хвостову латентність і передбачуваність, а не лише за загальний throughput.

Якщо зробите лише одну річ: встановіть vm.dirty_background_bytes і vm.dirty_bytes на розумні значення. Ця одна сім’я налаштувань ядра часто є різницею між «випадковими зависаннями» і платформою, якій можна довіряти.

← Попередня
ZFS Реплікація: Бездрамний спосіб обробки перейменувань і переміщень наборів даних
Наступна →
Винятки Defender: помилка, що робить шкідливе ПЗ невидимим

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