Ви патчите ядро, оновлюєте драйвер мережевої карти або встановлюєте «рекомендований» пакет для сховища від вендора. Вікно змін закрите. Графіки виглядають нормально годину. Потім латентність піднімається, як поганий ліфт: повільно, стабільно й у напрямку, де вам не хочеться бути.
Ось момент, коли починаються суперечки «це не може бути драйвер», бо оновлення «торкнулося лише мережі». Тогочас ваша база даних чекає, бо черги завершень сховища голодують через бурю переривань. Продакшен не переймається тим, якій команді належить проблема. Він переймається тим, що все повільно.
Що змінюється при оновленні драйверів
Драйвери — це не «лише драйвери». Вони вирішують, як планується апарат, як доставляються переривання, як розмірюються черги та як ядро сприймає плин часу під навантаженням. Оновлення драйвера може змінити продуктивність без жодної зміни в коді вашого застосунку. Це не теоретичний ризик — це вівторок.
Моделі регресій продуктивності, що зʼявляються після оновлень драйверів
- Стрибки латентності без втрати пропускної здатності: зміни в шляху завершення, зміни модерації переривань або зміни дефолтного глибини черги. Ваші дашборди показують стабільні MB/s, тоді як p99 латентність стає дикою.
- Падіння пропускної здатності при низькому CPU: відключені offload’и, лінк погоджено на нижчій швидкості, PCIe домовився про меншу кількість ліній або ввімкнулася консервативна політика прошивки.
- CPU росте, а «нічого більше не змінилося»: змінилася кількість векторів MSI-X, скинулася афініті IRQ, переключилися RPS/RFS, або новий драйвер прив’язав обробку до одного ядра.
- Регресія лише на деяких машинах: різна ревізія/прошивка, BIOS-дефолти, відмінності мікрокоду або драйвер, що відповідає трохи іншому ID пристрою.
- Регресія лише під конкуренцією: змінилася поведінка чергування; тести в однопотоковому режимі виглядають добре, але реальні навантаження — не однопотокові.
Де відбувається реальна шкода
У продакшені «продуктивність драйвера» зазвичай означає один із трьох конвеєрів:
- Пайплайн I/O сховища: block layer → scheduler → multipath (можливо) → HBA/NVMe драйвер → прошивка → носій. Оновлення можуть впливати на чергування, злиття, таймаути та відновлення при помилках.
- Мережевий пайплайн: netdev черги → GRO/LRO/offload’и → модерація переривань → NAPI polling → топологія CPU/NUMA. Оновлення драйвера можуть приховано змінити дефолтні розміри кілець і coalescing, що впливає на хвостову латентність.
- Пайплайн акселераторів (GPU/DPDK/RDMA): pinned memory, IOMMU mapping, hugepages, peer-to-peer DMA. «Дрібне» оновлення може перемикнути дефолт, який перетворює DMA на патоку.
Неприємна правда: ваше оновлення драйвера оновило не просто драйвер. Воно оновило припущення вашої системи про те, як переміщати байти.
Цитата, яку варто пам’ятати, бо це операційна версія гравітації:
Вернер Фогельс (парафраз): «Усе ламається постійно; проектуйте й експлуатуйте з таким очікуванням.»
І ще одна коротка жартівлива ремарка перед серйозністю: оновлення драйвера схоже на перерозташування гаража — нешкідливо, поки не знадобиться ключ о 2:00 ночі.
Факти та історичний контекст, які досі підкрадаються
Деякі «сучасні» регресії — це старі проблеми у новому обладнанні. Трохи історії допоможе передбачити, де продуктивність може впасти зі скелі.
- Блоковий шар Linux змінював напрямок кілька разів: від старих планувальників до multi-queue (blk-mq), зрушивши вузькі місця від злиття запитів до планування CPU та управління чергами.
- NCQ і tagged command queuing змінили значення «глибини черги»: глибші черги покращили пропускну здатність, але також виявили проблеми з хвостовою латентністю та справедливістю під змішаними навантаженнями.
- MSI/MSI-X замінили спільні переривання з важливих причин: але кількість векторів і їх мапування на CPU можуть зробити або зламати системи з високим I/O. Драйвери часто змінюють дефолти тут.
- Модерація переривань була винайдена для економії CPU: coalescing підвищує пропускну здатність, але може зруйнувати p99 латентність. Оновлення драйвера іноді «дбайливо» підвищують її.
- Offload’и (TSO/GSO/GRO/LRO) — двосічний меч: вони можуть покращити пропускну здатність і зменшити навантаження на CPU, але також приховати проблеми і додати латентність у дивних місцях. Оновлення можуть їх скидати.
- Автонеготація лінку була джерелом фейспалмів з ранніх часів Ethernet: одиночний збій авто-неґоціації може безшумно понизити вас з 25/40/100G до чогось соромного.
- Дефолти multipath еволюціонували разом з вендорами SAN: політики перевірки шляхів, queue_if_no_path та таймінги перемикання змінилися. «Працює» не означає «швидко».
- NVMe стандартизував багато, але прошивки все ще різняться: різні APST політики та поведінка відновлення при помилках можуть змінити латентність на порядки.
Жодне з цього не є академічним; це проявляється як «вчора все було добре».
План швидкої діагностики
Ви обмежені в часі. Користувачі кричать. Вікно змін давно закрите. Потрібна послідовність, що швидко виведе вас до правдоподібного вузького місця.
Перше: підтвердьте, що проблема реальна, і визначте «повільно» одним реченням
- Виберіть один спостережуваний параметр: p99 read latency, commit latency, network RTT, IOPS або CPU softirq.
- Виберіть порівняння: завтрашній базлайн або інший хост у тому ж кластері, який не оновлювався.
- Не «досліджуйте продуктивність» широко. Ви потонете в болоті.
Друге: вирішіть, який пайплайн винен
Використайте ці швидкі підказки:
- Високий iowait, зростає disk await, CPU стабільний → шлях сховища або пристрій/політика прошивки.
- Високий softirq, активність ksoftirqd, падіння пакетів → мережевий/переривальний шлях.
- Одне CPU ядро завантажене, інші простають → регресія IRQ affinity / мапування черг.
- Лише під навантаженням, не в ідлі → чергування, coalescing, планувальник або енергетичні стани.
Третє: знайдіть «скидання дефолту»
Після оновлень регресії продуктивності часто походять від повернення дефолту:
- розміри кілець NIC повернуті до малих значень
- втрачена або переставлена IRQ affinity
- NVMe енергозбереження знову ввімкнено
- змінений I/O scheduler
- змінена політика multipath
- переключено режим IOMMU
Четверте: доведіть це одним контрольованим тестом
Запустіть короткий, відтворюваний мікро-бенчмарк на ураженому хості й на відомо-робочому хості. Ви не прагнете виграти бенчмарк; ви прагнете ізолювати вимірну вісь регресії (латентність проти пропускної здатності проти CPU).
П’яте: оберіть найменш ризикову міру згладжування
У порядку пріоритету:
- Відкат драйвера/пакета прошивки (найшвидший спосіб «відновити відоме робоче»).
- Повторно застосувати відомі хороші налаштування (якщо відкат заблокований).
- Відсунути робоче навантаження від уражених хостів (купити час).
- Повний відкат ядра, якщо зміна повʼязана з ядром.
Ритуал після оновлення (нудна частина, що перемагає)
Ритуал звучить містично. Це не так. Це повторювана перевірка, яка запобігає спіралі «ми оновили й стало повільніше». Найкращі команди ставляться до оновлень драйверів як до міграцій бази даних: відкатні, виміряні й протестовані за тих самих умов.
1) Запишіть очікувані зміни перед оновленням
Не «має бути нормально». Конкретні очікування:
- Які пристрої зачеплено (PCI IDs, модель NIC, модель NVMe, прошивка HBA)?
- Які метрики можуть зрушити (латентність, пропускна здатність, CPU softirq, кількість помилок)?
- Який ваш план відкату (шлях пониження пакета, запис у завантажувач, можливе відновлення прошивки)?
2) Зніміть базлайн, який зможете відтворити
Ваш «базлайн» — це не скріншот дашборда з минулого місяця. Це набір виводів команд, що розповідає послідовну історію: версія ядра, версії модулів, версії прошивки, налаштування та невеликий результат бенчмарку.
3) Оновлюйте контрольовано, у зрізах
Спочатку canary-хости. Не тому, що модно, а тому, що регресії часто специфічні для апаратної конфігурації й ви хочете дізнатися про це на одному вузлі, а не на сорока.
4) Повторно перевірте дефолти, які вам важливі
Пакети драйверів іноді поставляються з новими дефолтами. Деякі покращують ситуацію. Деякі вважають вашу роботу «веб-сервінгом», коли ви насправді — «інтенсивна записна база даних з p99 SLOs». Сприймайте дефолти як пропозиції вендора, а не як закон.
5) Порівнюйте під навантаженням, а не під надією
Системи в ідлі брешуть. Більшість регресій проявляються під конкуренцією, на краю буферів, коли блоковий шар під тиском або коли модерація переривань змінює ритм завершень.
Ще один короткий жарт: найшвидший спосіб знайти регресію — оголосити «це оновлення безпечне» у перегляді змін. Всесвіт сприйме це особисто.
Практичні завдання: команди, виводи та рішення
Нижче — конкретні завдання, які ви можете виконати одразу після оновлення. Кожне включає: команду, що означає вивід, і яке рішення прийняти.
Завдання 1: Підтвердьте, що фактично змінилося (ядро + модулі драйверів)
cr0x@server:~$ uname -r
6.5.0-28-generic
cr0x@server:~$ modinfo ixgbe | egrep 'filename|version|srcversion'
filename: /lib/modules/6.5.0-28-generic/kernel/drivers/net/ethernet/intel/ixgbe/ixgbe.ko
version: 5.19.6-k
srcversion: 1A2B3C4D5E6F7A8B9C0D1E2
Значення: У вас є версія запущеного ядра і зібраний/завантажений драйвер. Якщо регресія зʼявилася «після оновлення», доведіть, що ви фактично працюєте з оновленими бінарниками.
Рішення: Якщо ядро/драйвер не відповідають очікуваному, зупиніться: ваш rollout/bootloader/фіксація пакетів поводиться неправильно. Виправте це перед будь-яким тонуванням.
Завдання 2: Ідентифікуйте версії прошивки для NIC і сховища
cr0x@server:~$ sudo ethtool -i eno1
driver: ixgbe
version: 5.19.6-k
firmware-version: 0x80000d7b
bus-info: 0000:3b:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: yes
Значення: Прошивка може змінювати поведінку навіть коли драйвер не змінювався. Деякі оновлення підтягують прошивку окремими пакетами або під час обслуговування.
Рішення: Якщо прошивка змінилася, включіть її в план відкату й у порівняння «відомо-хорошого». Не припускайте, що її можна швидко відкотити.
Завдання 3: Перевірте швидкість/ширину PCIe (мовчазний вбивця пропускної здатності)
cr0x@server:~$ sudo lspci -s 3b:00.0 -vv | egrep -i 'LnkCap:|LnkSta:'
LnkCap: Port #0, Speed 8GT/s, Width x8, ASPM not supported
LnkSta: Speed 2.5GT/s (downgraded), Width x4 (downgraded)
Значення: Пристрій домовився про зниження швидкості. Це може статися після змін BIOS, прошивки або через енергетичні особливості платформи.
Рішення: Якщо LnkSta показує пониження швидкості/ширини, припиніть переслідувати налаштування драйвера. Спочатку виправте фізичну/PCIe переговорну проблему (пересадіть плату, налаштування BIOS, енергетичні стани, відомі проблеми платформи).
Завдання 4: Визначте латентність сховища проти насичення (iostat)
cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0-28-generic (server) 01/22/2026 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
11.22 0.00 6.51 18.45 0.00 63.82
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %util await r_await w_await
nvme0n1 820.0 1250.0 52480.0 76800.0 0.0 0.0 97.8 9.82 6.10 12.40
Значення: %util близько до 100% вказує на насичення. await показує середню латентність; розподіл read/write await допомагає ідентифікувати, який патерн погіршився.
Рішення: Якщо await стрибнув після оновлення при схожій пропускній здатності, підозрюйте енергетичні стани, налаштування черг, зміни scheduler або відновлення після помилок у прошивці. Якщо %util низький, але await високий — підозрюйте проблеми шляху або таймаути.
Завдання 5: Шукайте регресії NVMe power state та APST
cr0x@server:~$ sudo nvme get-feature /dev/nvme0 -f 0x0c -H
get-feature:0xc (Autonomous Power State Transition), Current value:0x00000001
APSTE: 1
APST Entries:
Entry[ 0] Idle Time Prior to Transition (ITPT): 1000 ms
Entry[ 0] Idle Transition Power State (ITPS): 3
Значення: APST увімкнено може бути нормальним для ноутбуків і катастрофою для серверів з чутливою латентністю, залежно від пристрою/прошивки.
Рішення: Якщо латентність регресувала й APST несподівано увімкнено, тимчасово перевірте вимкнення та подивіться, чи p99 відновлюється. Потім зробіть зміни постійними через відповідний механізм вашого дистрибутива/ядра.
Завдання 6: Перевірте блоковий планувальник і налаштування черг
cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[mq-deadline] none
cr0x@server:~$ cat /sys/block/nvme0n1/queue/nr_requests
1024
cr0x@server:~$ cat /sys/block/nvme0n1/queue/read_ahead_kb
128
Значення: Вибір scheduler і глибина черги впливають на справедливість і латентність під конкуренцією. Оновлення іноді змінюють дефолтний планувальник або ліміти запитів.
Рішення: Якщо scheduler відрізняється від відомо-хорошого, вирівняйте його і повторно протестуйте. Якщо nr_requests зменшено — ви можете бачити падіння пропускної здатності при паралельному навантаженні; якщо збільшено — хвостову латентність може зростати.
Завдання 7: Перевірте стан multipath (регресії SAN люблять ховатись тут)
cr0x@server:~$ sudo multipath -ll
mpatha (3600508b400105e210000900000490000) dm-2 IBM,2145
size=2.0T features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
|-+- policy='service-time 0' prio=50 status=active
| `- 5:0:0:1 sdb 8:16 active ready running
`-+- policy='service-time 0' prio=10 status=enabled
`- 6:0:0:1 sdc 8:32 active ready running
Значення: Пріоритети шляхів і політики мають значення. Зміна політики може направити більше I/O по повільнішому шляху або призвести до дергань під час перемикання.
Рішення: Якщо вибір активного шляху відрізняється після оновлення, порівняйте multipath.conf і активні параметри карти. Виправте політику/обробку ALUA перед тим, як звинувачувати базу даних.
Завдання 8: Перевірте dmesg на скидання драйвера, таймаути або флапи лінку
cr0x@server:~$ sudo dmesg -T | egrep -i 'nvme|ixgbe|timeout|reset|link is|error' | tail -n 20
[Wed Jan 22 10:12:41 2026] nvme nvme0: I/O 123 QID 5 timeout, completion polled
[Wed Jan 22 10:12:41 2026] nvme nvme0: Abort status: 0x371
[Wed Jan 22 10:14:03 2026] ixgbe 0000:3b:00.0 eno1: NIC Link is Up 10 Gbps, Flow Control: RX/TX
Значення: Таймаути й аборти — це не «шум». Вони вбивають продуктивність задовго до того, як стануть outage.
Рішення: Якщо після оновлення ви бачите нові таймаути, припиніть тонування і почніть ізоляцію: сумісність прошивки, енергетичні функції, кабель/SFP, PCIe або баг. Розгляньте негайний відкат.
Завдання 9: Підтвердіть швидкість лінку NIC і погоджені налаштування
cr0x@server:~$ sudo ethtool eno1 | egrep 'Speed:|Duplex:|Auto-negotiation:|Link detected:'
Speed: 10000Mb/s
Duplex: Full
Auto-negotiation: on
Link detected: yes
Значення: Якщо швидкість неправильна, усе вище страждає. Це крок «перевір кабель», але в 2026 році іноді кабель — це дефолт прошивки.
Рішення: Якщо швидкість впала — виправляйте це спочатку. Якщо швидкість вірна — переходьте до offload’ів і розмірів кілець.
Завдання 10: Перевірте мережеві offload’и (оновлення люблять скидати їх)
cr0x@server:~$ sudo ethtool -k eno1 | egrep 'tcp-segmentation-offload|generic-segmentation-offload|generic-receive-offload|rx-checksumming|tx-checksumming'
rx-checksumming: on
tx-checksumming: on
tcp-segmentation-offload: off
generic-segmentation-offload: on
generic-receive-offload: on
Значення: Один відключений offload може перемістити витрати на CPU і зменшити пропускну здатність. Але бездумне ввімкнення всього може збільшити латентність або зламати спостережуваність.
Рішення: Порівняйте з відомо-хорошим. Якщо TSO переключився в off після оновлення і CPU softirq виріс — увімкніть його назад і повторіть тест. Якщо проблема в латентності — розгляньте налаштування coalescing замість ввімкнення всіх offload’ів.
Завдання 11: Перевірте розміри кілець і лічильники drop
cr0x@server:~$ sudo ethtool -g eno1
Ring parameters for eno1:
Pre-set maximums:
RX: 4096
RX Mini: 0
RX Jumbo: 0
TX: 4096
Current hardware settings:
RX: 512
RX Mini: 0
RX Jumbo: 0
TX: 512
cr0x@server:~$ ip -s link show dev eno1 | tail -n 8
RX: bytes packets errors dropped missed mcast
9876543210 12345678 0 421 0 0
TX: bytes packets errors dropped carrier collsns
8765432109 11223344 0 0 0 0
Значення: Малі кільця й зростання drops — класична пост-оновлювальна регресія, коли дефолти змінено. Drops примушують ретрансляції, що виглядає як «випадкова латентність».
Рішення: Якщо drops ростуть і кільця малі відносно max, обережно збільште розміри кілець і повторно протестуйте. Якщо drops лишаються — перевіряйте coalescing і розподіл IRQ.
Завдання 12: Перевірте розподіл переривань (регресія IRQ affinity)
cr0x@server:~$ awk '/eno1/ {print}' /proc/interrupts | head -n 6
121: 9843321 0 0 0 PCI-MSI 524288-edge eno1-TxRx-0
122: 0 0 0 0 PCI-MSI 524289-edge eno1-TxRx-1
123: 0 0 0 0 PCI-MSI 524290-edge eno1-TxRx-2
124: 0 0 0 0 PCI-MSI 524291-edge eno1-TxRx-3
Значення: Коли всі переривання падають на один CPU — це податок на продуктивність і генератор латентності. Після оновлення може змінитися поведінка irqbalance або налаштування в драйвері.
Рішення: Якщо один вектор гарячий, а інші холодні — виправте афініті (або RPS/RFS) і повторіть тест. Якщо вектори не створюються, перевірте параметри драйвера і чи увімкнено MSI-X.
Завдання 13: Заміряйте навантаження softirq (проблеми мережевого шляху)
cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.5.0-28-generic (server) 01/22/2026 _x86_64_ (32 CPU)
12:20:41 PM CPU %usr %nice %sys %iowait %irq %soft %idle
12:20:42 PM all 10.20 0.00 6.80 1.10 0.30 8.90 72.70
12:20:42 PM 7 2.00 0.00 4.00 0.00 0.00 65.00 29.00
Значення: Одне CPU, що тоне в %soft, вказує на дисбаланс обробки переривань/пакетів. Часто це скидання налаштувань драйвера, а не «застосунок став повільнішим».
Рішення: Якщо одне CPU перевантажене в %soft — відкоригуйте IRQ affinity/RPS або поверніться до налаштувань offload/coalescing. Якщо softirq низький, а латентність висока — вузьке місце, ймовірно, в іншому місці.
Завдання 14: Перевірте конкурентність I/O з fio (контрольний короткий тест)
cr0x@server:~$ sudo fio --name=randread --filename=/dev/nvme0n1 --direct=1 --ioengine=libaio --rw=randread --bs=4k --iodepth=64 --numjobs=4 --runtime=30 --time_based --group_reporting
randread: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=64
...
read: IOPS=220k, BW=859MiB/s (901MB/s)(25.2GiB/30001msec)
slat (nsec): min=920, max=110893, avg=3210.44, stdev=1800.12
clat (usec): min=60, max=9800, avg=112.30, stdev=95.20
lat (usec): min=62, max=9810, avg=115.60, stdev=95.50
clat percentiles (usec):
| 50.00th=[ 98], 90.00th=[ 180], 99.00th=[ 420], 99.90th=[1200]
Значення: Ви отримуєте IOPS, пропускну здатність і розподіл латентності. Перцентилі — те, що відчувають користувачі. Регресія драйвера часто проявляється в p99/p99.9 до того, як середні значення сильно зрушать.
Рішення: Порівняйте з базлайном. Якщо p99/p99.9 суттєво погіршилися — не сперечайтеся: відкатуйте або виправляйте налаштування, які змінилися.
Завдання 15: Перевірте режим IOMMU (неочікувані сюрпризи DMA)
cr0x@server:~$ dmesg -T | egrep -i 'DMAR|IOMMU|AMD-Vi' | head -n 8
[Wed Jan 22 09:01:11 2026] DMAR: IOMMU enabled
[Wed Jan 22 09:01:11 2026] DMAR: Intel(R) Virtualization Technology for Directed I/O
Значення: Деякі оновлення драйверів взаємодіють з дефолтами IOMMU. Для певних високопропускних пристроїв неправильна конфігурація може додати накладні витрати або спричинити конфлікти мапувань.
Рішення: Якщо продуктивність регресувала і режим IOMMU змінився останнім часом — перевірте рекомендації платформи для вашого навантаження (особливо для DPDK/RDMA/GPU). Не відключайте його навмання; тестуйте на canary.
Завдання 16: Підтвердіть політику частоти CPU (енергозбереження може виглядати як регресія драйвера)
cr0x@server:~$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
powersave
cr0x@server:~$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
1200000
Значення: Після оновлень або змін BIOS губернатори можуть переключитися. Низька частота CPU може підняти латентність переривань та завершень I/O.
Рішення: Якщо governor змінився з performance на powersave — виправте це спочатку, інакше ваше тонування буде ганятися за рухомою мішенню.
Три міні-історії з корпоративного життя
Міні-історія 1: Інцидент через неправильне припущення
Вони запускали кластер для аналізу на основі сховища. Нічого екзотичного: Linux, NVMe кеш, мережевий об’єктний стор, багато паралельних читань. Пришло оновлення ядра з «фіксами безпеки та оновленими драйверами». Тікет зміни був акуратним. Команда припустила, що драйвери неважливі, бо «у нас і так CPU-bound».
Через два дні нічні джоби почали пропускати дедлайни. Не катастрофа. Достатньо, щоб викликати щоденну нараду. Графіки були заплутані: пропускна здатність виглядала приблизно стабільною, але час виконання джобів зростав. CPU був нижчий, ніж раніше. Люди сприйняли це як добру новину.
Насправді симптомом була хвостова латентність в маленьких читаннях. Нова комбінація NVMe драйвера/прошивки знову увімкнула агресивну політику енергозбереження. Середня латентність майже не змінилася; p99.9 подвоїлася. Навантаження складалося з рою дрібних читань, тож повільний хвіст домінував у загальному часі.
Неправильним припущенням було не «драйвери неважливі», а тонше: «якщо пропускна здатність стабільна, сховище в порядку». Пропускна здатність — зручна метрика, бо її легко графічно показати. Латентність виплачує вашу зарплату.
Вони вимкнули проблемний енергетичний стан на канарях, підтвердили відновлення перцентилів короткими fio-тестами, а потім застосували налаштування по кластеру. Пізніше вони відкотили прошивку для повної впевненості. Постмортем має один рядок, що запамʼятався: ми виміряли не те першим.
Міні-історія 2: Оптимізація, що зіграла зворотний ефект
Платформна команда хотіла знизити навантаження CPU на зайнятих API-вузлах. Після оновлення драйвера NIC вони помітили більше доступних налаштувань для модерації переривань. Збільшили coalescing, бо графіки обіцяли менше переривань. CPU впав. Вони оголосили перемогу.
Потім прийшов інцидент у чистому вигляді: клієнтська латентність під час пікових годин повільно зростала. Не стрибок, а дрейф — важче для PagerDuty, ідеально підриває SLA без гучних тупиків. Їхні дашборди показували зниження CPU і стабільну мережеву пропускну здатність. Знову — втішні метрики.
Корінна причина: coalescing збільшив час очікування пакетів перед обробкою. Добре для пропускної здатності. Погано для хвостової латентності. Гірше, це взаємодіяло з патерном запитів, чутливим до джиттера, тож p99 підскочив настільки, що спричинив каскадні повторні запити на рівні застосунку.
Оптимізація зіграла зворотний ефект, бо оптимізувала не ту метрику. Вони ганялися за CPU, а не за латентністю. NIC робив саме те, що просили: об’єднував роботу. Продакшен робив те, що завжди робить: карав неправильний компроміс.
Виправлення було хірургічне: відкотити coalescing до відомо-хорошого профілю, потім налаштувати розподіл IRQ і розміри кілець. CPU трохи виріс, але p99 стабілізувався. Вони зробили висновок: «низький CPU» не є метою. Це обмеження, яке ви керуєте, виконуючи SLO.
Міні-історія 3: Нудна, але правильна практика, що врятувала день
Фінансова компанія мала політику змін, над якою всі кепкували: для оновлень драйверів вимагали «бандл до/після». Не великий процес. Скрипт збирав версію ядра, версії модулів, версії прошивки, ключові sysfs-налаштування і 30-секундний fio плюс простий iperf у контрольованому середовищі.
В день, коли прийшло оновлення драйвера сховища, один canary вузол показав невелике, але стабільне зростання перцентилів запису. Нічого «померло». Якби вони розкочували по кластеру — база даних пригальмувала б під час end-of-day обробки, і це стало б реальним інцидентом.
Бандл до/після зробив регресію очевидною: змінився scheduler, nr_requests і параметр таймауту. Виправлення було таке ж нудне: зафіксувати пакет драйвера, відновити scheduler і налаштування черг, і відкрити тікет у вендора з конкретними diff’ами.
Оскільки їх ловили на канарі, нікому не довелося пояснювати керівництву, чому «дрібне оновлення» спричинило видиму для клієнтів повільність. Команда все ще кепкувала з політики, але вже менш охоче. Нудьга у операціях недооцінена.
Поширені помилки: симптом → корінна причина → виправлення
1) «Пропускна здатність в порядку, але застосунок повільний»
Симптом: MB/s стабільні; p95/p99 латентність гірша; зʼявляються таймаути/повторні запити.
Корінна причина: Зросла модерація переривань; увімкнені APST/енергозбереження; змінилася поведінка чергування; шлях завершення перемістився на менше CPU.
Виправлення: Перевірте coalescing, NVMe енергетичні функції, розподіл IRQ. Використовуйте percentiles fio, а не середню латентність.
2) «CPU впав після оновлення, і продуктивність впала теж»
Симптом: Менше CPU; менше пропускної здатності; вища латентність запитів.
Корінна причина: Offload’и були відключені; лінк погодився на нижчу швидкість; пристрій перейшов на менше PCIe ліній; розміри кілець зменшилися.
Виправлення: Перевірте ethtool offload’и і швидкість лінку; перевірте PCIe LnkSta; збільшіть кільця, якщо ростуть drops.
3) «Лише один вузол повільний»
Симптом: Один хост регресував; сусіди в порядку при тому ж софті.
Корінна причина: Несумісність прошивки; інша топологія PCIe/NUMA; зсув налаштувань BIOS; відмінності мікрокоду; зміна ревізії пристрою.
Виправлення: Порівняйте lspci -vv, ethtool -i, nvme id-ctrl між вузлами; вирівняйте прошивку/BIOS; не припускайте однорідності.
4) «Після оновлення зʼявилися мережеві дропи»
Симптом: Зростають RX dropped counters; ретрансляції; джиттер.
Корінна причина: Зменшені розміри кілець; афініті переривань зруйноване; надто агресивне coalescing; змінилася кількість RSS черг.
Виправлення: Збільшіть кільця; переконайтесь, що кілька черг активні; виправте афініті; переоцініть coalescing для латентності.
5) «У dmesg зʼявляються таймаути сховища, але диск здоровий»
Симптом: nvme timeout/abort рядки; час від часу зависає; немає SMART-помилок.
Корінна причина: Несумісність драйвера/прошивки; переходи енергетичних станів; скидання контролера; проблеми сигналізації PCIe, які проявилися через нову синхронізацію драйвера.
Виправлення: Сприймайте це як проблему сумісності або платформи: тестуйте відкат, налаштуйте енергетичні функції, перевірте PCIe переговори, ескалюйте з відтворюваними логами.
6) «Після оновлення multipath `up`, але I/O повільніший»
Симптом: multipath -ll виглядає нормально; латентність гірша під навантаженням; перемикання шляхів шумить.
Корінна причина: Змінилася політика (service-time vs round-robin); ALUA пріоритети неправильно інтерпретовані; поведінка queue_if_no_path змінилася; таймінг path checker’а помінявся.
Виправлення: Перевірте політику/пріоритет; вирівняйте multipath.conf; підтвердьте поведінку ALUA; повторно протестуйте під контрольованим навантаженням.
Чеклисти / покроковий план
Перед оновленням (15 хвилин, що запобігають 5-годинному інциденту)
- Визначте поверхню ризику: які драйвери/прошивки змінюються (NIC, HBA, NVMe, GPU, RDMA).
- Зніміть бандл базлайна: uname -r, modinfo, ethtool -i/-k, lspci -vv (для ключових пристроїв), scheduler/queue sysfs-налаштування, multipath -ll якщо застосовується.
- Виберіть 2–3 золоті метрики: мінімум одна метрика пропускної здатності і одна хвостова латентність. Запишіть їх у тикет зміни.
- Сплануйте відкат: кроки пониження пакета, попередній запис ядра і будь-які обмеження на відкат прошивки.
- Оберіть canary-хости: хости, що репрезентують варіації апаратури, а не просто «найменш завантажені».
Під час вікна оновлення (робіть менше, але цілеспрямовано)
- Оновлюйте спочатку лише canary-сегмент.
- Після перезавантаження перевірте запущені ядро/модулі.
- Заново перевірте PCIe ширину/швидкість для пристроїв, до яких торкалися.
- Підтвердіть погоджену швидкість NIC та offload-налаштування.
- Запустіть короткий стандартизований тест (fio для сховища; легку перевірку throughput/латентності для мережі, якщо є безпечний шлях).
- Порівняйте з базлайном, а не з вашим настроєм.
Після оновлення (частина «ритуал»)
- Повторно застосуйте намірені налаштування: IRQ affinity, розміри кілець, налаштування scheduler, політики енергії — усе, що входить до вашого відомо-хорошого базлайна.
- Слідкуйте за відкладеними регресіями: енергетичні стани і відновлення після помилок можуть виглядати нормально, поки змінюється форма навантаження.
- Розширюйте розгортання поступово: якщо canary в порядку, продовжуйте пакетами з паузою достатньою для спостереження реальної поведінки під навантаженням.
- Архівуйте бандл після стану: він стане вашим новим базлайном, якщо все добре, або доказом, якщо стало гірше.
Якщо підозрюєте регресію: драбина ескалації
- Зупиніть кровотечу: злийте навантаження з уражених вузлів або зменшіть паралелізм.
- Відтворіть на одному вузлі: запустіть контрольований бенчмарк і збирайте логи.
- Відкотіть найменше можливе: спочатку пакет драйвера або налаштування; повний відкат ядра, якщо потрібно.
- Тільки потім тонувати: тонування без розуміння того, що змінилося, перетворить систему на крихку, яку розуміє лише одна людина.
Питання й відповіді
1) Чому оновлення драйверів викликають регресії продуктивності, навіть якщо апарат той самий?
Тому що драйвери кодують політику: розміри черг, поведінка переривань, дефолти offload’ів, енергоменеджмент, відновлення при помилках. Зміна політики змінює продуктивність.
2) Краще оновлювати ядро та драйвери окремо чи разом?
Окремо легше атрибутувати, разом іноді неминуче. Якщо мусите робити разом — збільшіть час для canary і зніміть більше «до/після» доказів.
3) Яка найшвидша перевірка для виявлення регресії NIC?
Почніть зі швидкості лінку/дуплексу і лічильників drop. Якщо ви домовилися вниз або є дропи — все інше відволікає.
4) Яка найшвидша перевірка для регресії сховища?
iostat для await/%util плюс dmesg на предмет таймаутів/скидань. Якщо ядро таймаутить I/O — історія продуктивності вже написана.
5) Чи варто завжди вимикати NVMe APST на серверах?
Ні. Треба зробити базлайнинг. Деякі пристрої поводяться добре; інші карають за хвостову латентність. Якщо у вас p99 SLOs — протестуйте APST вкл/викл з fio percentiles.
6) Чи може irqbalance «виправити» проблеми з перериваннями автоматично?
Іноді. Воно також може скасувати навмисне привʼязування або зробити вибір, який коректний для розподілу CPU в середньому, але поганий для латентності. Сприймайте його як інструмент, а не гарантію.
7) Чому збільшення розмірів кілець допомогло пропускній здатності, а не латентності?
Більші кільця зменшують дропи й покращують пропускну здатність під спалахами, але вони також можуть додати буферизації, що підвищує латентність. Якщо латентність — пріоритет, налаштовуйте coalescing і розподіл IRQ уважно.
8) Коли відкат кращий за тонування?
Якщо ви бачите нові помилки/таймаути/скидання — відкатуйте. Якщо це чистий зсув продуктивності без помилок і ви можете прив’язати його до зміни дефолтів — тонування може бути доречним, але спочатку на canary.
9) Як уникнути «театру бенчмарків» після оновлень?
Використовуйте короткі стандартизовані тести і порівнюйте той самий тест на відомо-хорошому хості. Фіксуйте перцентилі, розподіл CPU і ключові налаштування. Не підбирайте дані вибірково.
10) Що робити, якщо регресія з’являється лише під піковим трафіком і я не можу відтворити її?
Шукайте індикатори насичення: дропи, чергування, одиночні CPU-гарячі точки %softirq, пониження PCIe під навантаженням і переходи енергетичних станів. Якщо не вдається відтворити — все одно можна корелювати.
Висновок: наступні кроки, які ви реально можете зробити
Оновлення драйверів не страшні. Невимірені оновлення драйверів — страшні. Лікування не в героїзмі; воно в повторюваному ритуалі, що ставить продуктивність як властивість коректності.
- Зберіть бандл базлайна (версії, прошивки, налаштування, один короткий fio, одна NIC sanity-перевірка) і зробіть його обовʼязковим для змін драйверів.
- Прийміть план швидкої діагностики: визначте «повільно», оберіть пайплайн, шукайте скидання дефолту, доведіть одним тестом, помʼякшіть безпечно.
- Канарте кожне оновлення драйвера по варіантах апаратури. Якщо не можете канарити — ви не оновлюєте, ви граєте в азартні ігри.
- Запишіть відомо-хороші налаштування і повторно застосовуйте їх після оновлень. Дефолти не є вашим конфігураційним менеджментом.
- Віддавайте перевагу відкату над «магічним тонуванням», коли бачите таймаути/скидання/помилки. Регресії з помилками — це як практика для аутеджів.
Якщо ви робитимете це послідовно, «продуктивність після оновлення» перестане бути драмою й стане пунктом чеклиста. Продакшен це любить.