«Але ж це на NVMe.» Це речення закривало більше інцидентів, ніж вирішувало. Ви купили швидкий накопичувач, можете його бенчмарки зробити, але VM все одно ніби думає довше, ніж треба. Логіни гальмують. Встановлення пакетів повільне. Ваша база даних каже, що вона «I/O bound», що одночасно і допомагає, і не дає відповіді.
Прихована причина зазвичай не в сирому пропускному каналі. Це затримка — особливо затримка запису — спричинена набором дефолтів, які безпечні, загальні й іноді жорстокі: семантика sync, режими кешу, черги, поведінка тонкого провізування, посилення CoW, реплікація сховища та конкуренція на хості. NVMe не виправляє погані рішення; воно просто прискорює їхні наслідки.
Прихована причина: ваша VM платить за затримки, яких ви не заклали
Маркетинг NVMe святкує пропускну здатність. Користувачі ж відчувають кінцеві затримки — 95-й/99-й процентиль затримок для «малих синхронних операцій, які повинні завершитися перед наступною дією». «Повільність» VM часто — це тисяча дрібних sync-записів, які чемно стоять у черзі за чиєюсь уявою про надійність.
У Proxmox шлях сховища — це шаруватий торт:
- Гостьова файлова система та семантика застосунків (fsync, O_DIRECT, journaling, barriers)
- Модель віртуального пристрою (virtio-scsi vs virtio-blk, черги, iothreads)
- QEMU cache mode (writeback/writethrough/none/directsync) та AIO
- Файлова система хоста та менеджер томів (ZFS, LVM-thin, directory, Ceph RBD)
- Блок-лейер хоста (схедулер, поведінка merge, multipath)
- Поводження фізичного пристрою (фірмваре NVMe, thermal throttling, SLC cache, power-loss protection)
«Прихована причина» зазвичай — невідповідність між очікуваннями гостя і гарантіями хоста. Гість робить sync-записи, а десь унизу стек каже: «Добре, я підтверджу це, коли воно фактично буде в безпечному стані». Це хороша інженерія. Але саме тому встановлення невеликого пакета може виглядати як робота з податками.
Порада з думкою: перестаньте гнатися за заголовковими MB/s. Почніть вимірювати IOPS при низькій глибині черги, затримку fsync і час очікування на хості. Більшість інцидентів «повільний NVMe» — це або (a) затримка sync-записів (ZFS, Ceph, write barriers), (b) конкуренція/чергування (гучний сусід), або (c) «оптимізація» на кшталт discard, компресії чи снапшотів, що погано взаємодіє з вашим навантаженням.
Анекдот №1: NVMe — це як дати вашому стажеру спортивну машину — вражає, доки він не вирішить поїхати мальовничим маршрутом до дата-центру.
Цікаві факти та історія (бо у дефолтів є бекграунд)
- Режими кешу QEMU існують тому, що сховище іноді брешуть. У ранні роки віртуалізації «writeback» міг бути швидким, але ризикованим, якщо нижчий стек реально не зберігав дані.
- ZFS створювали навколо контрольних сум і copy-on-write. Це дає цілісність і снапшоти, але змінює патерни записів і може посилювати дрібні випадкові записи залежно від recordsize/volblocksize.
- Головна перевага NVMe — паралелізм. Протокол підтримує багато submission/completion черг, але VM з однією чергою все ще може обмежуватися CPU і локами.
- Linux I/O schedulers еволюціонували під шпиндельні диски. Деякі досі корисні для справедливості та контролю затримки; інші просто додають накладні витрати на NVMe шляхи, які не потребують переупорядкування.
- Write barriers і flushes стали суворішими з часом. Файлові системи навчилися важким шляхом, що «швидко» без впорядкованої надійності стає «швидким коруптом» після втрати живлення.
- Thin provisioning став популярним через дорожнечу ємності. Але тонкі пули можуть фрагментуватися, і їхня метадані можуть стати мовчазним обмежувачем продуктивності, якщо їх не моніторити.
- TRIM/discard не є «безкоштовним». Це допомагає довговічності SSD і сталій продуктивності, але онлайн-discard може створювати періодичні сплески затримки в залежності від фірмвару диска і навантаження.
- Ceph сильний у розподіленій надійності. Ця надійність додає мережеву та реплікаційну затримку; NVMe на вузлах OSD не скасовує витрати на кворум і підтвердження.
Швидкий план діагностики
Вам не потрібен тиждень налаштувань. Потрібні 20 хвилин контрольованого спостереження. Ось порядок, який найшвидше виявляє вузьке місце в продакшені.
Перш за все: підтвердьте, що симптом — це затримка I/O, а не CPU steal чи дефіцит пам’яті
- Всередині гостя: перевірте iowait і затримки диска. Якщо CPU завантажений або пам’ять свапиться, налаштування сховища — театральність.
- На хості: перевірте поведінку, схожу на CPU steal (перевантаження хоста), KSM, ballooning і свапінг.
По-друге: визначте бекенд сховища та його семантику надійності
- ZFS: поведінка sync, наявність/якість SLOG, recordsize/volblocksize, компресія, special vdevs.
- LVM-thin: використання даних/метаданих, поведінка discard, ознаки фрагментації.
- Ceph RBD: затримка на мережевому шляху, commit/apply OSD, реплікація, налаштування клієнта.
- Directory/ext4/xfs: опції монтирования хоста, write cache, barriers, стан файлової системи.
По-третє: перевірте модель пристрою VM і чергування
- virtio-scsi з iothread і кількома чергами, коли це доречно.
- Правильний cache mode для бекенда (і чесність щодо ризиків).
По-четверте: знайдіть конкуренцію та кінцеві затримки
- Шукайте VM, яка робить важкі записи, бекапи або злиття снапшотів.
- Вимірюйте використання диска і глибину черги на хості, а не тільки всередині VM.
По-п’яте: підтвердіть, що сам NVMe не є вузьким місцем
- Thermal throttling, фірмварні особливості, швидкість лінку PCIe та налаштування живлення можуть перетворити «швидкий» на «вихований».
Правило прийняття рішення: якщо ви не можете вказати одну з (a) затримка sync, (b) чергування/конкуренція, (c) CPU/пам’ять, (d) помилкова конфігурація бекенду — ви все ще гадаєте. Продовжуйте вимірювати.
Практичні завдання: команди, виводи та рішення
Це перевірки, які я реально запускаю. Кожне завдання містить реалістичний фрагмент виводу та яке рішення з цього робити.
Завдання 1: Визначити бекенд диска VM в Proxmox
cr0x@server:~$ qm config 104 | egrep -i 'scsi|virtio|ide|sata|boot|machine'
boot: order=scsi0;net0
machine: q35
scsi0: nvme-zfs:vm-104-disk-0,iothread=1,cache=none,discard=on,ssd=1,size=80G
scsihw: virtio-scsi-single
Що це означає: Ця VM використовує том на ZFS, scsihw — virtio-scsi-single, cache=none, iothread ввімкнено, discard on.
Рішення: Якщо VM чутлива до затримок і робить sync-записи, ваші наступні перевірки — шлях sync у ZFS і чи не обмежує virtio-scsi-single паралелізм черг.
Завдання 2: Підтвердити тип сховища на хості (ZFS vs LVM-thin vs directory)
cr0x@server:~$ pvesm status
Name Type Status Total Used Available %
local dir active 19684272 4181248 15403024 21.24%
nvme-zfs zfspool active 960123904 412345344 547778560 42.95%
ceph-rbd rbd active 0 0 0 0.00%
Що це означає: Диск VM знаходиться на пулі ZFS з ім’ям nvme-zfs.
Рішення: Зосередьтеся на властивостях dataset/zvol ZFS (sync, volblocksize, compression) і чи є належний SLOG.
Завдання 3: Перевірити затримку, видиму з VM (швидко і грубо)
cr0x@server:~$ iostat -x 1 5
Linux 6.1.0 (guest) 02/04/2026 _x86_64_ (4 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
8.02 0.00 3.11 22.70 0.00 66.17
Device r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 3.00 45.00 120.0 2480.0 114.7 2.80 58.20 8.20 61.60 2.10 10.20
Що це означає: w_await ≈ 62 ms. Це не «швидко для NVMe». Це означає, що щось змушує записи чекати.
Рішення: Шукайте обмеження на шляху sync-записів: ZFS sync, реплікацію Ceph, cache mode або хостову конкуренцію.
Завдання 4: Перевірити затримку диска та чергування на хості
cr0x@server:~$ iostat -x 1 5
Linux 6.5.13-pve (pve-host) 02/04/2026 _x86_64_ (16 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
10.40 0.00 4.80 18.20 0.00 66.60
Device r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
nvme0n1 20.00 800.00 900.0 68000.0 167.5 45.20 55.10 9.80 56.30 0.45 99.00
Що це означає: %util на піку і avgqu-sz велике. Пристрій насичений або пригнічений, і затримка зростає.
Рішення: Знайдіть хто пише, чи це бекапи/скраби, і чи «швидкий» диск досягає межі стійких записів або thermal throttling.
Завдання 5: Визначити головних споживачів I/O на хості
cr0x@server:~$ pidstat -d 1 5
Linux 6.5.13-pve (pve-host) 02/04/2026 _x86_64_ (16 CPU)
# Time UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
12:01:10 0 21456 0.00 82000.00 12000.00 vzdump
12:01:10 0 17890 0.00 12000.00 0.00 qemu-system-x86
12:01:10 0 17891 0.00 11800.00 0.00 qemu-system-x86
Що це означає: vzdump гасить записи. Хост зайнятий бекапами, що ймовірно викликає сплески затримки VM.
Рішення: Обмежте швидкість бекапів, перемістіть їх з основного пулу або заплануйте їх поза піком. Якщо ви це вже робите, перевірте поведінку злиття снапшотів і бекенд сховища.
Завдання 6: Перевірити стан пулу ZFS і індикатори затримки
cr0x@server:~$ zpool status -v nvme-zfs
pool: nvme-zfs
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
nvme-zfs ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
errors: No known data errors
Що це означає: Очевидних помилок немає. «Здоров’я» — не те саме, що продуктивність.
Рішення: Перейдіть до властивостей ZFS і поведінки sync; також перевірте наявність SLOG і чи він підходить.
Завдання 7: Перевірити властивості dataset/zvol ZFS, що впливають на затримку
cr0x@server:~$ zfs get -r compression,atime,recordsize,logbias,sync,primarycache,secondarycache nvme-zfs
NAME PROPERTY VALUE SOURCE
nvme-zfs compression zstd local
nvme-zfs atime off local
nvme-zfs recordsize 128K local
nvme-zfs logbias latency local
nvme-zfs sync standard local
nvme-zfs primarycache all default
nvme-zfs secondarycache all default
Що це означає: sync=standard означає, що sync-запити виконуються. Добре. Якщо ваше навантаження робить багато fsync, затримка залежить від здатності пулу безпечно зафіксувати дані.
Рішення: Якщо затримка sync висока і вам важлива коректність, додайте SLOG з захистом від втрати живлення або переробіть патерни записів. Не вимикайте sync=disabled, якщо не готові пояснювати втрату даних.
Завдання 8: Підтвердити, чи існує SLOG і чи він окремий
cr0x@server:~$ zpool status nvme-zfs | sed -n '1,40p'
pool: nvme-zfs
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
nvme-zfs ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
errors: No known data errors
Що це означає: Жодного logs vdev не виявлено. Sync-записи мають фіксуватися на основному vdev.
Рішення: Якщо ви запускаєте бази даних, поштові сервери, CI-runner’и або щось, що багато fsync робить, подумайте про виділений SLOG з PLP. Якщо не можете — прийміть затримку як ціну надійності.
Завдання 9: Виміряти затримку ZFS в реальному часі
cr0x@server:~$ zpool iostat -v nvme-zfs 1 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
nvme-zfs 393G 519G 40 820 1.2M 70.1M
nvme0n1 393G 519G 40 820 1.2M 70.1M
---------- ----- ----- ----- ----- ----- -----
Що це означає: Багато операцій запису і високий пропуск. Це не показує затримку прямо, але каже, що пул зайнятий і треба корелювати з iostat -x на хості і часом бекапів/скрабів.
Рішення: Якщо «навантаження» співпадає з болем користувачів, потрібно ізоляція навантажень: окремі пули, цілі для бекапів або обмеження I/O через cgroups / обмеження Proxmox.
Завдання 10: Перевірити стан NVMe і підказки про троттлінг
cr0x@server:~$ nvme smart-log /dev/nvme0n1 | egrep -i 'temperature|warning|critical|media|power_cycles|unsafe_shutdowns'
critical_warning : 0x00
temperature : 72 C
available_spare : 100%
media_errors : 0
power_cycles : 38
unsafe_shutdowns : 2
Що це означає: 72°C — тепло. Деякі диски троттлять у цьому діапазоні залежно від моделі і потоку повітря. Unsafe shutdowns також важливі для цілісності, якщо ви покладаєтеся на летючі кеші.
Рішення: Виправте охолодження і підтвердіть, що пристрій не знижує швидкість при тривалих записах. Якщо бачите проблеми з термінами — «повільна VM» фактично «повільна фізика».
Завдання 11: Перевірити швидкість/ширину PCIe (часто мовчазна проблема)
cr0x@server:~$ lspci -s 03:00.0 -vv | egrep -i 'LnkSta|NVMe'
Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller
LnkSta: Speed 8GT/s (ok), Width x2 (downgraded)
Що це означає: Диск працює на PCIe x2, а не x4. Це може обмежувати пропуск і іноді посилювати ефекти конкуренції.
Рішення: Перемістіть пристрій у слот з повними лініями, виправте налаштування BIOS або припиніть ділити лінії з іншими пристроями.
Завдання 12: Перевірити I/O scheduler для NVMe на хості
cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[mq-deadline] none kyber bfq
Що це означає: Активний mq-deadline. Часто це розумний дефолт для змішаних навантажень, бо контролює затримку під навантаженням.
Рішення: Якщо бачите сплески затримки під конкуренцією, тримайте scheduler, орієнтований на затримку (mq-deadline або kyber). Якщо у вас одне навантаження і ви хочете мінімальних накладних витрат — тестуйте none, але лише з вимірюваннями.
Завдання 13: Інспектувати конфігурацію virtio-scsi і черг у VM
cr0x@server:~$ qm config 104 | egrep -i 'scsihw|iothread|queues|numa|cpu|machine'
machine: q35
scsihw: virtio-scsi-single
scsi0: nvme-zfs:vm-104-disk-0,iothread=1,cache=none,discard=on,ssd=1,size=80G
cpu: host
numa: 0
Що це означає: virtio-scsi-single використовує одну чергу за дизайном. Для деяких навантажень це стає вузьким місцем на мульти-vCPU гостях.
Рішення: Розгляньте virtio-scsi-pci з кількома чергами для паралельного I/O, якщо гостю це корисно. Не міняйте сліпо: бази даних часто більше цінують узгоджену затримку, ніж сирий паралелізм.
Завдання 14: Перевірити тиск пам’яті на хості (маскується під «повільний диск»)
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 62Gi 54Gi 1.2Gi 2.1Gi 6.8Gi 3.0Gi
Swap: 8.0Gi 2.6Gi 5.4Gi
Що це означає: Використовується swap і доступна пам’ять мала. Під тиском reclaim і свапінг можуть затримувати I/O шляхи і vCPU гостя.
Рішення: Виправте overcommit, політику ballooning або додайте RAM. Налаштування сховища не виправить свапінг.
Завдання 15: Виявити поведінку TRIM/discard чи вони спричиняють сплески
cr0x@server:~$ systemctl status fstrim.timer | sed -n '1,12p'
● fstrim.timer - Discard unused blocks once a week
Loaded: loaded (/lib/systemd/system/fstrim.timer; enabled; preset: enabled)
Active: active (waiting) since Mon 2026-02-03 00:00:00 UTC; 1 day 12h ago
Trigger: Mon 2026-02-10 00:00:00 UTC; 5 days left
Що це означає: Щотижневий TRIM заплановано. Це зазвичай краще, ніж безперервний discard для узгодженості затримок.
Рішення: Віддавайте перевагу періодичному TRIM над постійним discard для багатьох серверних навантажень. Якщо ви використовуєте discard=on в конфігурації диска VM, перевірте, чи це не створює сплесків затримки під високою зміною даних.
Завдання 16: Виявити злиття снапшотів/бекапів (класичне «чому саме зараз?»)
cr0x@server:~$ zfs list -t snapshot -o name,used,creation -s creation | tail -n 5
nvme-zfs/vm-104-disk-0@vzdump-2026_02_04-000001 1.2G Tue Feb 4 00:00 2026
nvme-zfs/vm-107-disk-0@replica-2026_02_04-001500 800M Tue Feb 4 00:15 2026
nvme-zfs/vm-104-disk-0@replica-2026_02_04-001500 650M Tue Feb 4 00:15 2026
nvme-zfs/vm-104-disk-0@replica-2026_02_04-003000 700M Tue Feb 4 00:30 2026
nvme-zfs/vm-104-disk-0@replica-2026_02_04-004500 720M Tue Feb 4 00:45 2026
Що це означає: Часті снапшоти від бекапів/реплікації. Хронічний створення снапшотів може збільшувати посилення записів на CoW-системах і погіршувати локальність.
Рішення: Зменште частоту снапшотів для томів з великим обігом записів, використайте окремі цілі бекапу або налаштуйте ретеншн, щоб уникнути довгих ланцюгів старих снапшотів, що «чіпляють» блоки.
Глибше: що насправді робить NVMe повільним
1) Пропускна здатність бреше; затримка говорить правду
Більшість тикетів «VM повільна» — це люди, які кажуть, що взаємодія зупиняється: SSH на секунду довше, apt призупиняється, сайти підлаговують. Це — малі I/O операції з послідовною залежністю. Один fsync у 40 ms не покаже проблему пропускної здатності, але може зіпсувати журнал транзакцій, apt install або журнальну файлову систему.
NVMe блискуче працює при високих IOPS і пропускній здатності, але лише якщо стек може утримувати черги заповненими і стабільно завершувати роботу. Навантаження VM часто працює при низькій глибині черги з частими flush-ами. Якщо ваш бекенд перетворює ці flush-и в дорогі очікування, ваш NVMe стає дуже швидким пристроєм, що здебільшого чекає дозволу.
2) Sync-записи: ZFS і вартість чесності
За замовчуванням ZFS: коли застосунок просить надійності, ZFS ставиться до цього серйозно. Це означає, що sync-записи фіксуються на стабільному сховищі перед підтвердженням. На пулі без виділеного ZIL/SLOG ці коміти потрапляють на основний vdev(и). На одному NVMe це може бути нормально — допоки ви не змішаєте навантаження, не викличете тривалі записи або не потрапите на фірмварну поведінку, яка робить flush-и дорогими.
Пастка — думати «один NVMe = миттєвий sync». Багато споживчих NVMe пришвидшують записи через летючі кеші і внутрішні алгоритми. Якщо вони не мають захисту від втрати живлення, вони будуть обережними щодо семантики flush, і можуть виконувати внутрішню чистку, що призводить до сплесків затримки. ZFS не читає маркетингові тексти; він читає обіцянки вашого диска.
Робіть: для навантажень з інтенсивним sync використовуйте enterprise NVMe з PLP або окремий SLOG, спеціально розрахований на низьку затримку sync-записів.
Уникайте: встановлення sync=disabled як «фікса продуктивності», якщо ви не готові втрачати підтверджені записи при краші. Це не гіпотетично; таке трапляється в реальних відмовах.
3) Режими кешу QEMU: продуктивність — це контракт, а не відчуття
У Proxmox режим кешу диска змінює взаємодію QEMU з page cache хоста і поведінку flush. Коротко:
- cache=none: direct I/O (O_DIRECT) обходить page cache хоста. Часто корисно для зменшення подвійного кешування і передбачуваності затримки.
- cache=writeback: може бути швидким, але покладається на кешування хоста. Також підвищує ризик, якщо нижчий стек або обладнання «бреше» про надійність.
- cache=writethrough/directsync: більш консервативні; можуть підвищувати затримку.
Немає «універсально кращого». Є лише «краще для ваших вимог до надійності і продуктивності». Якщо ви запускаєте бази даних і цінуєте коректність, узгодьте cache mode і бекенд так, щоб flush-и означали те, що гість очікує.
4) virtio-scsi-single: одна черга, що всіх обмежує
virtio-scsi-single існує не просто так: для сумісності і простоти. Але воно також посилає I/O через одну чергу, що може стати точкою контенції CPU і локів для мульти-vCPU гостьових ОС з паралельним I/O.
Якщо ваше навантаження виконує кілька незалежних I/O потоків — наприклад build-сервери, кілька контейнерів в одній VM або зайнятий файловий сервер — одна черга може створити штучно високу затримку навіть коли NVMe відносно вільний.
Робіть: розгляньте virtio-scsi-pci з відповідними налаштуваннями черг і iothread=1 для пристроїв, які від цього виграють.
Уникайте: додавання «більше черг» без спостережень. Деякі навантаження погіршуються при збільшенні конкуренції, бо хвостова затримка розповсюджується під навантаженням.
5) Thin provisioning: повільне підкрадання метаданих
LVM-thin цілком працездатний і розповсюджений у Proxmox. Але тонкі пули мають два фатальні місця продуктивності:
- Тиск на метадані: коли метадані щільні або часто оновлюються, виникають сплески затримки.
- Фрагментація: з часом алокації розкидаються, особливо при churn снапшотів і випадкових записах.
Якщо ви використовуєте thin пули як магію — вони нагадають, що вони облікові системи з хобі блокового пристрою.
6) Хронічні снапшоти і бекапи: CoW не безкоштовний
Proxmox робить бекапи і снапшоти простими, що добре. Але це також легко перетворюється на постійну фонова машину, яка посилює записи:
- Часті снапшоти закріплюють старі блоки.
- Випадкові записи повинні алокувати нові блоки (CoW), що підвищує фрагментацію.
- Процеси бекапу читають цілі диски і можуть виштовхнути кеші, збільшуючи затримку для інтерактивних робочих навантажень.
Бекапи потрібні. Але «кожні 15 хвилин для всього» — це політика від того, кого будуть дзвонити серед ночі.
7) Конкуренція: гучний сусід зазвичай — це ви
Один NVMe може обробляти вражаючі IOPS, але змішані читання/записи з sync-flush-ами можуть його все одно насичувати. Гірше: одна VM з великими послідовними записами (ціль бекапу, агрегація логів) може зруйнувати затримку для іншої VM з дрібними випадковими sync-записами (база даних). Обидва «ок» окремо. Разом — вони б’ються.
Ізоляція переважає геройські налаштування. Окремі пули. Окремі пристрої. Окремий трафік бекапів. Або хоча б використовуйте I/O-ліміти Proxmox для забезпечення чесності.
8) Сам NVMe: SLC cache, фірмваре і терміни
Споживчі NVMe часто рекламують пікову продуктивність завдяки SLC-кешу. При тривалих записах вони різко падають. Ви цього не помітите в бенчмарку 30 секунд; помітите о 02:00, коли бекапи і реплікація йдуть 90 хвилин.
Терміни — ще тихий вбивця. Контролери NVMe будуть троттлити, щоб захистити себе, і ваше «швидке сховище» перетворюється на «добре поводжене сховище». Це створює скажений графік: пилка продуктивності, коли пристрій гріється і охолоджується.
Анекдот №2: Більше загадок продуктивності я бачив вирішеними вентилятором, ніж докторською дисертацією — і це і смішно, і гучно.
9) Мислення про надійність: цитата, що варто пам’ятати
Парафразована ідея (з посиланням): Gene Kim часто підкреслює операційний принцип, що поліпшення потоку вимагає зменшення незавершеної роботи і затримки зворотного зв’язку, а не лише додавання потужності.
Проблеми зі сховищем часто — проблеми потоку: надто багато фонових задач, надто багато черг і замало видимості затримок.
Три корпоративні міні-історії з реального світу
Міні-історія 1: Інцидент через хибне припущення («NVMe означає, що sync дешевий»)
Середня SaaS-компанія мігрувала кілька критичних PostgreSQL VM на новий кластер Proxmox. Обіцянка була проста: локальні NVMe дзеркала, ZFS для снапшотів і Proxmox replication для швидкого відновлення. Перший тиждень пройшов спокійно. Другий тиждень приніс повільний відмовний інцидент під час піку.
Тир тиру почали таймаути. Не скрізь — але достатньо, щоб збити з пантелику. CPU був в нормі. Мережа теж. Всередині DB VM iostat показував огидні очікування записів. Команда першою думала, що проблема у файловій системі гостя і стала підлаштовувати опції mount. Це не допомогло.
На хості стало ясно: sync-записи накопичувалися за іншими записами, і NVMe показував довгі хвостові затримки під тривалим змішаним навантаженням. Хибне припущення було в тому, що NVMe робить fsync практично безкоштовним. Ні. Воно робить можливим бути швидким — якщо ваш пристрій і конфігурація підтримують низьку затримку для durable commit.
Фікс був банальний: додали SLOG з PLP, зменшили частоту снапшотів на зволах баз даних і перенесли реплікацію поза пік. Історія «NVMe швидке» перетворилася на «надійність має ціну — платіть її явно».
Міні-історія 2: Оптимізація, що відпалила назад («увімкнути discard скрізь»)
IT-команда стандартизувала шаблони Proxmox. Вони ввімкнули discard=on для кожного диска VM і налаштували файлові системи гостя на безперервний discard, бо це виглядало красиво: кращий знос SSD, краща звільнена ємність, менше сюрпризів. Впровадження йшло плавно і з відчуттям зрілості.
Потім служба підтримки почала бачити «випадкові затримки» у VM. Не повні зависання. Просто періодичні багатосекундні паузи. Найгірше було на завантажених Windows термінальних серверах і кількох Linux VM з інтенсивною тимчасовою активністю. Користувачі казали, що «клавіатура на секунду перестає реагувати». Інженери казали «не відтворюється», що миліше, ніж «ще не відтворюється».
Метрики хоста врешті корелювали паузи зі сплесками discard. Деякі моделі NVMe це витримували, інші ж перетворювали discard на внутрішні GC події з помітними затримками. Під віртуалізацією ці сплески посилювалися, бо багато гостей одночасно робили ту саму «оптимізацію».
Відкат був хірургічний: відключили безперервний discard у гостях, зберегли періодичний fstrim, і вмикали discard=on тільки для томів, які дійсно потребували звільнення місця онлайн. Оптимізація не була «поганою» сама по собі; вона провалилася тому, що «всюди і завжди» — не стратегія продуктивності.
Міні-історія 3: Нудна практика, що врятувала день («виміряти хвостові затримки і ізолювати бекапи»)
Фінансова команда вела Proxmox для внутрішніх інструментів і кількох чутливих до затримок сервісів. Нічого гламурного. У них було просте правило: бекапи не мають ділити пул з продукційними write-heavy базами, якщо немає вимірюваного і забезпеченого I/O бюджету.
Вони реалізували окреме сховище: один пул для VM-дисків і другий для бекап-цілей. Також малій дашборд зосереджувався на 95/99 процентилях затримки диска на хостах в робочий час. Не просто середні. Хвостова затримка — саме той показник, що відповідає людським скаргам.
Одного вівторка розгорнули новий сервіс з чатливим логуванням і агресивною локальною політикою зберігання. Він постійно писав. Дашборд засяяв за хвилини, і завдяки ізоляції бекапів зона ураження залишилася малою. Вони обмежили шумну VM, підправили логування і життя продовжилося.
Без героїчних післяінцидентних рев’ю. Без драми «NVMe зламався». Просто запобіжні заходи, які передбачали, що хтось колись зробить щось ентузіастичне з дисковими записами. І вони виявилися правими.
Типові помилки: симптом → корінь → виправлення
-
Симптом: VM відчувається повільною, встановлення пакетів затримується, бази даних повідомляють про високий fsync time.
Корінь: Затримка sync-записів на ZFS без відповідного SLOG або на споживчому NVMe під тривалим змішаним навантаженням.
Виправлення: Додати SLOG з PLP або enterprise NVMe; зменшити churn снапшотів; ізолювати гучних писаків; зберігати
sync=standardдля коректності. -
Симптом: Випадкові багатосекундні паузи у кількох VM у нестандартний час.
Корінь: Сплески discard/TRIM або фонова обслуговування (fstrim, GC диска), що спричиняє піки затримки.
Виправлення: Віддавати перевагу періодичному
fstrimнад безперервним discard; тестуватиdiscard=onвибірково; перевіряти терміни NVMe і фірмвар. -
Симптом: Високе використання диска на хості, але окремі VM показують низький пропуск; усе «просто повільно».
Корінь: Чергування/конкуренція (бекап, реплікація, scrub, інша VM), що насичує пристрій дрібними записами і flush-ами.
Виправлення: Перемістити бекапи з пулу; перенести важкі завдання; додати I/O-ліміти; розділити пули для різних класів затримки.
-
Симптом: Одна VM з кількома vCPU не виходить за межі помірних IOPS; затримка зростає при паралельних задачах.
Корінь:
virtio-scsi-single— вузька черга або відсутній iothread.Виправлення: Використовувати
virtio-scsi-pciі ввімкнути iothread; розглянути multiqueue там, де підтримуються; перетестувати за допомогоюfioв гості. -
Симптом: Продуктивність хороша 30–60 секунд, потім колапс під тривалими записами.
Корінь: Витрачення SLC-кешу NVMe і троттлінг при тривалих записах.
Виправлення: Обирати диски, розраховані на тривалі записи; перепровізувати; покращити охолодження; відокремити бекапи/потоки ingest.
-
Симптом: Після увімкнення компресії/дедупу «для ефективності» затримка погіршилася.
Корінь: Накладні витрати CPU і посилення; dedup особливо важкий без потрібної пам’яті і підходящого навантаження.
Виправлення: Використовувати компресію обдумано (зазвичай так); уникати dedup для VM-дисків, якщо немає доказаного випадку; вимірювати вплив на CPU і затримки.
-
Симптом: «NVMe швидкий», але хост свапиться; VM гальмують під тиском пам’яті.
Корінь: Перевантаження пам’яті на хості; свапінг і reclaim затримують I/O і планування CPU.
Виправлення: Виправити розмір RAM, ballooning і ліміти ARC ZFS; не дозволяти свапінг на гіпервізорах, якщо ви не знаєте, навіщо це.
-
Симптом: Бенчмарки сховища виглядають добре, але реальні додатки повільні.
Корінь: Бенчмарки тестують послідовну пропускну здатність або глибокі черги; ваш додаток — sync-важкий при низькій глибині черги.
Виправлення: Бенчмарк того, що має значення: low-QD random reads/writes, fsync latency і хвостові процентилі — всередині гостя і на хості.
Чеклісти / покроковий план
Крок за кроком: діагностика однієї повільної VM без варіння океану
- Підтвердьте, що проблема стабільна. Отримайте часовий інтервал і корелюйте з бекапами, скрабами, реплікацією і деплойментами.
- Всередині гостя: перевірте
iostat -xіvmstat 1. Якщо iowait високий — рухайтеся далі. Якщо активний свап — вирішіть пам’ять першочергово. - На хості: запустіть
iostat -xдля NVMe-пристрою. Дивіться на високийawait, великеavgqu-szі забите%util. - Знайдіть писача:
pidstat -dі корелюйте з PID-миqemu-system-x86або інструментами бекапу. - Визначте бекенд:
pvesm statusіqm config. ZFS? LVM-thin? Ceph? Різні сценарії потребують різних дій. - Перевірте модель пристрою VM:
virtio-scsi-singlevsvirtio-scsi-pci, iothread ввімкнений, cache mode відповідний. - Перевірте реальність NVMe:
nvme smart-log(терміни),lspci -vv(ширина ліній), і впевніться, що немає троттлінгу. - Змінюйте по одному параметру. Повторно тестуйте оригінальну користувацьку операцію (не тільки синтетичний тест).
Чекліст: «зробіть це, уникайте того» для продуктивності сховища в Proxmox
- Робіть: моніторте процентилі затримки диска на хостах. Уникайте: покладання на графіки середньої пропускної здатності.
- Робіть: ізолюйте трафік бекапів. Уникайте: запускати важкі бекапи на тому ж пулі, що й низькозатратні бази даних у піковий час.
- Робіть: використовуйте PLP-пристрої для прискорення sync. Уникайте: споживчих дисків для очікувань щодо durability журнала записів.
- Робіть: тримайте політику снапшотів усвідомленою. Уникайте: високочастотних снапшотів на томах з великим обігом без вимірів.
- Робіть: обирайте virtio і черги навмисно. Уникайте: залишатися на дефолтах, якщо є докази, що вони є вузьким місцем.
- Робіть: ставтесь до discard як до інструмента. Уникайте: вмикати безперервний discard скрізь, бо це «гарно звучить».
FAQ
1) Чому моя VM повільна, якщо NVMe бенчмаркує гігабайти за секунду?
Бо ваше навантаження, ймовірно, залежить від низької глибини черги і синхронної затримки (fsync/flush), а не від послідовної пропускної здатності. Вимірюйте await і часи fsync, а не тільки MB/s.
2) Чи варто ставити ZFS sync=disabled, щоб поліпшити затримку?
Лише якщо ви готові прийняти втрату підтверджених записів при краші. Для баз даних і більшості станних сервісів це поганий компроміс. Виправляйте шлях sync з належним обладнанням (SLOG з PLP/enterprise NVMe) або ізоляцією навантажень.
3) Чи завжди краще ставити cache=none в Proxmox?
Ні. Часто це хороший дефолт для передбачуваності і уникнення подвійного кешування, але «найкращий» режим залежить від бекенду і вимог надійності. Розглядайте cache mode як частину контракту коректності.
4) Що не так з virtio-scsi-single?
Нічого — поки вам не потрібен паралелізм. Воно використовує одну чергу, яка може стати вузьким місцем для багатопотокових I/O навантажень. Якщо бачите CPU/lock контенцію і обмежені IOPS — розгляньте virtio-scsi-pci з кількома чергами і iothreads.
5) Снапшоти завжди повільні?
Снапшоти не обов’язково повільні, але часті снапшоти на томах з великим обігом збільшують накладні витрати CoW і фрагментацію. Більші проблеми проявляються під час merge-ів, бекапів і тривалих випадкових записів.
6) Чи покращує увімкнення discard продуктивність?
Може покращити стійку поведінку і звільнення простору, але також може вводити сплески затримки. Багато середовищ краще почуваються з періодичним fstrim, ніж з безперервним discard, особливо для багатьох VM.
7) Як дізнатися, чи NVMe троттлить?
Перевірте температуру через nvme smart-log і корелюйте падіння продуктивності з підвищенням температури. Також стежте за пилкоподібними патернами в затримці і пропускній здатності при тривалих записах.
8) Чи варто змінювати Linux I/O scheduler для NVMe?
Іноді. none може зменшити накладні витрати, а mq-deadline або kyber можуть покращити справедливість затримок під конкуренцією. Обирайте, базуючись на вимірюванні хвостових затримок, а не на ідеології.
9) Чому бекапи роблять інтерактивні VM повільними, навіть якщо бекапи «більш читаючі»?
Читання може виштовхувати кеші і збільшувати чергування пристрою, а бекапи на основі снапшотів можуть викликати додаткову роботу з метаданими. Якщо бекапи конкурують за той самий пул, чутливі до затримки навантаження відчують це.
10) Який найефективніший єдиний фікс для «повільних VM на швидкому сховищі»?
Ізоляція. Окремі пули (або принаймні суворі I/O-ліміти) для різних класів затримки і припинення змішування штормів бекапу/scrub/реплікації з інтерактивними транзакційними навантаженнями.
Практичні наступні кроки
Якщо ви хочете, щоб VM перестала відчуватися повільною, зробіть це в порядку:
- Вимірюйте затримку, а не пропускну здатність. Захопіть
iostat -xна гості та хості під час вікна скарг. - Визначте бекенд. ZFS vs LVM-thin vs Ceph змінює, що «нормально» і який «фікс» має сенс.
- Знайдіть конкуренцію. Бекапи і churn снапшотів — часті винуватці. Підтвердіть через
pidstat -dі кореляцію часу. - Виправте шлях надійності чесно. Якщо вам потрібні швидкі sync-записи — використайте обладнання, яке може їх безпечно забезпечити (SLOG з PLP/enterprise NVMe) або прийміть затримку як ціну коректності.
- Налаштовуйте черги VM навмисно. Якщо ви на
virtio-scsi-singleі навантаження паралельне — перейдіть на кращу модель пристрою і валідируйте реальним тестом навантаження. - Припиніть «оптимізувати» глобально. Discard, агресивні снапшоти і надмірні хитрощі з кешуванням — це чудові способи створити флотові флуктуації. Змінюйте під класи навантажень.
Виграш — це не лише швидші VM. Це менше загадкових тикетів, менше нічних дзвінків і стек сховища, що поводиться як система, а не як чутка.