Debian 13: результати fio обманюють — як тестувати сховище, не обманюючи себе

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

Ви запустили fio на Debian 13, отримали героїчні цифри й оголосили перемогу. Потім у продакшені все впало під час першої реіндексації, бекапу чи компакції, і «швидкі» диски раптом поводилися як мережева шара 2008 року.

Це нормально. Не тому, що Linux-підсистема сховища погана — а тому, що бенчмарки легко ненавмисно сфальсифікувати. fio не брешe; ми самі обманюємо себе хибними припущеннями, зручними дефолтами та тестами, які не відповідають робочому навантаженню.

Що насправді вимірює fio (і чого він не вимірює)

fio — це генератор навантаження. Він подає I/O з певними шаблонами (випадкове vs послідовне, читання vs запис, змішане, розміри блоків, глибина черги, режими синхронізації) і звітує про те, що сталося. І тільки це. Він не знає, чи ви тестували кеш сторінок замість диска. Він не знає, що ваш SSD ось-ось тротлінгуватиме по теплу. Він не знає, що контролер RAID підтверджує записи, які ще перебувають у нестійкому кеші. Він не знає, що ваша база робить 4k випадкових читань, а бенчмарк робив 1М послідовних записів.

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

  • Що ви намагаєтеся передбачити? Пікова пропускна спроможність? P99 затримка при конкурентності? Час відновлення? Поведінка хвоста під час сплесків записів?
  • Що є одиницею істини? IOPS — не істина, якщо користувачі зважують затримку. Пропускна здатність — не істина, якщо вузьке місце — синхронні малі записи.
  • Яка система під тестом? Сам диск, стек ОС, файлова система, менеджер томів, шифрування, мережеве сховище, контролерний кеш та планування CPU — все має значення. Визначте, що входить у сферу тестування.

Бенчмарки не повинні бути «чесними». Вони мають бути передбачувальними. Якщо ваш тест не відповідає формі I/O у продакшені, це генератор упевненості, а не бенчмарк.

Цікаві факти та контекст (чому сьогоднішні помилки передбачувані)

  • Кеш сторінок Linux був «посилювачем бенчмарків» з 1990-х. Буферизований ввід-вивід може вимірювати швидкість ОЗП і видавати її за швидкість диска, якщо ви не вимкнете прямий ввід-вивід або не перевищите пам’ять.
  • Продуктивність SSD залежить від внутрішнього стану. Нові NAND поводяться інакше, ніж у steady-state після тривалих записів; передкондиціонування стало формальною частиною тестування, бо ранні огляди SSD були фактично фантазією.
  • Глибина черги популяризувалася в епосі SAN для підприємств. Багато «QD32» легенд походить з епохи контролерів; це не автоматично релевантно для низьколатентних NVMe і сучасних додатків з обмеженою конкурентністю.
  • NVMe змінило сторону CPU у зберіганні. Шляхи подачі/завершення I/O стали дешевшими і більш паралельними, тому прив’язка CPU та розподіл IRQ можуть стати «вузьким місцем диска», навіть коли медіа в порядку.
  • Кешування записів завжди було спірним. Контролери, які підтверджують записи до їхньої стійкості, дали світу чудові бенчмарки і інколи незабутні аварії; акумуляторний кеш був компромісом.
  • Файлові системи історично оптимізувалися під різні режими відмов. Дефолти ext4 спрямовані на широку безпеку; XFS часто показує себе краще при паралельній пропускній здатності; системи copy-on-write міняють певні затримки заради снапшотів і контрольних сум.
  • Проблеми вирівнювання старші за SSD. Неправильне вирівнювання розділів шкодило RAID-стрипам і досі б’є, коли ваші 4k логічні блоки не відповідають підлягаючій геометрії.
  • Процентилі затримки перемістилися з академії в операції. Індустрія боляче навчилася, що середнє ховає біль; P99 і P99.9 стали операційно важливими разом із масштабом веб-систем.

Одна цитата, варта пам’ятати під час бенчмаркінгу: Сподівання — не стратегія. (Vince Lombardi)

Як бенчмарки ненавмисно шахраюють: типові підозрювані

1) Ви протестували ОЗП (кеш сторінок), а не диск

Якщо ви запускаєте файлові fio-завдання без --direct=1, Linux може задовольняти читання з кешу та поглинати записи в пам’ять, а потім скидати їх пізніше. Ваші результати виглядають приголомшливо. Ваша база не отримує таких чисел, коли мусить чекати реальної стійкості.

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

2) Розмір запиту та семантика синхронізації не відповідають реальності

Багато продакшн-систем виконують малі синхронні записи (commit журналу, WAL fsync, оновлення метаданих). Бенчмарк, що робить 1M послідовних записів з великою глибиною черги, вимірює зовсім інший всесвіт.

3) Глибина черги стає костюмом продуктивності

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

4) Пристрій у «чистому» стані, якого продакшн ніколи не бачить

Поведінка FTL SSD залежить від вільних блоків і тиску на збірку сміття. Короткі тести на порожніх дисках можуть бути нереально швидкими. Довгі тести можуть стати повільними. Обидва твердження правдиві; лише одне передбачувальне.

5) Ви виміряли інший шлях, ніж той, який використовує ваше навантаження

Тести на блочному пристрої можуть оминати накладні витрати файлової системи, журналювання, опції монтовання та суперечку за метадані. Файлові тести включають це — але також включають розташування директорій та поведінку вільного простору. Обирайте свідомо.

6) CPU, IRQ та NUMA тихо стають «продуктивністю сховища»

На NVMe часто вузьким місцем стає обробка переривань, конкуренція на одній черзі або погана аффініті. Ваш «дисковий бенчмарк» перетворюється на бенчмарк планування CPU. Це не помилка — якщо ви це помічаєте.

7) Енергоменеджмент, тротлінг та політики прошивки змінюють правила під час тесту

SSD та NVMe-диски можуть термічно тротлінгувати. CPU може знижувати частоту. Ноутбуки поводяться як ноутбуки. Сервери — як сервіри з енергозбереженням. Ваш тест стає тестом радіаторів, а не IOPS.

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

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

Це не «приємні додатки». Це те, як ви не дасте fio перетворитися на театральне шоу продуктивності на Debian 13.

Завдання 1: Перевірте, який пристрій ви тестуєте (і чи він віртуальний)

cr0x@server:~$ lsblk -o NAME,MODEL,SIZE,ROTA,TRAN,TYPE,MOUNTPOINTS
NAME        MODEL               SIZE ROTA TRAN TYPE MOUNTPOINTS
sda         INTEL SSDSC2KB48     447G    0 sata disk
├─sda1                            1G    0      part /boot
└─sda2                          446G    0      part
  └─vg0-lv0                      400G    0      lvm  /
nvme0n1     SAMSUNG MZVL21T0      1.8T    0 nvme disk
└─nvme0n1p1                        1.8T  0      part /data

Що це означає: Ви не зможете інтерпретувати результати, якщо не знаєте, чи працюєте з SATA SSD, NVMe, віртуальним диском або шаром LVM. ROTA=0 вказує на неротаційний пристрій, але це все ще включає SATA SSD та NVMe.

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

Завдання 2: Визначте активний планувальник I/O (щоб уникнути випадкового чергування)

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

Що це означає: Планувальник у квадратних дужках — активний. NVMe часто добре працює з none або mq-deadline, але «правильний» вибір залежить від вашого навантаження та дефолтів ядра.

Рішення: Тримайте його послідовним між тестами. Якщо ви бенчмаркуєте для продакшну, відповідність планувальника продакшну важлива. Якщо діагностуєте дивні затримки, протестуйте обидва none і mq-deadline.

Завдання 3: Підтвердіть логічні/фізичні розміри блоків і ризик вирівнювання

cr0x@server:~$ sudo blockdev --getss /dev/nvme0n1
512
cr0x@server:~$ sudo blockdev --getpbsz /dev/nvme0n1
4096

Що це означає: 512-байтові логічні сектори, 4k фізичні. Неправильне вирівнювання може спричиняти штрафи read-modify-write, особливо для малих записів.

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

Завдання 4: Перевірте файлову систему та опції монтування (журналювання та бар’єри важливі)

cr0x@server:~$ findmnt -no SOURCE,FSTYPE,OPTIONS /data
/dev/nvme0n1p1 ext4 rw,relatime,errors=remount-ro

Що це означає: Опції як noatime, barrier (або історично nobarrier) і режим журналювання впливають на поведінку записів.

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

Завдання 5: Виявляйте налаштування кеша записів (і чи чесний ваш бенчмарк)

cr0x@server:~$ sudo hdparm -W /dev/sda | head
/dev/sda:
 write-caching =  1 (on)

Що це означає: Кеш записів увімкнений може бути прийнятний для SSD з захистом від втрати живлення; небезпечний для споживчих дисків або контролерів без захисту, якщо ви вимикаєте бар’єри або обманюєтеся щодо flush.

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

Завдання 6: Спостерігайте стан пристрою та тепловий стан (перш ніж звинувачувати fio)

cr0x@server:~$ sudo smartctl -a /dev/nvme0n1 | sed -n '1,40p'
smartctl 7.4 2023-08-01 r5530 [x86_64-linux-6.12.0-amd64] (local build)
=== START OF INFORMATION SECTION ===
Model Number:                       SAMSUNG MZVL21T0
Serial Number:                      S6XXXXXXXXXXXX
Firmware Version:                   3B2QGXA7
Total NVM Capacity:                 1,900,000,000,000 [1.90 TB]
...
Temperature:                        68 Celsius
Available Spare:                    100%
Percentage Used:                    2%

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

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

Завдання 7: Підтвердіть, що ви можете обійти кеш сторінок (перевірка direct I/O)

cr0x@server:~$ fio --name=direct-check --filename=/data/fio.test --size=2G --rw=read --bs=128k --direct=1 --ioengine=libaio --iodepth=16 --numjobs=1 --runtime=10 --time_based --group_reporting
direct-check: (g=0): rw=read, bs=(R) 128KiB-128KiB, (W) 128KiB-128KiB, (T) 128KiB-128KiB, ioengine=libaio, iodepth=16
fio-3.38
Starting 1 process
direct-check: Laying out IO file (1 file / 2048MiB)
Jobs: 1 (f=1): [R(1)][100.0%][r=912MiB/s][r=7296 IOPS][eta 00m:00s]
direct-check: (groupid=0, jobs=1): err= 0: pid=21199: Mon Dec 29 11:09:10 2025
  read: IOPS=7200, BW=900MiB/s (944MB/s)(9000MiB/10001msec)

Що це означає: --direct=1 запитує direct I/O (обхід кеша сторінок). Якщо ви його опустите, читання можуть задовольнятися пам’яттю після першого проходу.

Рішення: Використовуйте --direct=1 для характеристики пристрою. Використовуйте буферизований ввід-вивід лише коли ви спеціально моделюєте додаток, що покладається на кеш (і тоді вимірюйте розмір кешу та його поведінку теж).

Завдання 8: Доведіть собі, що буферизовані читання можуть шахраювати

cr0x@server:~$ fio --name=buffered-cheat --filename=/data/fio.test --size=2G --rw=read --bs=128k --direct=0 --ioengine=psync --iodepth=1 --numjobs=1 --runtime=10 --time_based --group_reporting
buffered-cheat: (g=0): rw=read, bs=(R) 128KiB-128KiB, (W) 128KiB-128KiB, (T) 128KiB-128KiB, ioengine=psync, iodepth=1
fio-3.38
Starting 1 process
Jobs: 1 (f=1): [R(1)][100.0%][r=5240MiB/s][r=41920 IOPS][eta 00m:00s]
buffered-cheat: (groupid=0, jobs=1): err= 0: pid=21305: Mon Dec 29 11:11:33 2025
  read: IOPS=41000, BW=5120MiB/s (5370MB/s)(51200MiB/10001msec)

Що це означає: Така пропускна здатність підозріло близька до поведінки пам’яті на багатьох системах. Вітаємо, ви протестували кеш.

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

Завдання 9: Виміряйте процентилі затримки (бо середні — брехуни)

cr0x@server:~$ fio --name=latency-4k --filename=/dev/nvme0n1 --rw=randread --bs=4k --direct=1 --ioengine=io_uring --iodepth=32 --numjobs=4 --runtime=30 --time_based --group_reporting --lat_percentiles=1
latency-4k: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=io_uring, iodepth=32
fio-3.38
Starting 4 processes
Jobs: 4 (f=4): [r(4)][100.0%][r=1680MiB/s][r=430k IOPS][eta 00m:00s]
latency-4k: (groupid=0, jobs=4): err= 0: pid=21601: Mon Dec 29 11:14:22 2025
  read: IOPS=430k, BW=1680MiB/s (1762MB/s)(50400MiB/30001msec)
    clat percentiles (usec):
     |  1.00th=[   66],  5.00th=[   72], 10.00th=[   76], 50.00th=[   90]
     | 90.00th=[  120], 95.00th=[  140], 99.00th=[  210], 99.90th=[  420]
     | 99.99th=[  920]

Що це означає: Медіана виглядає чудово, P99 — прийнятно, а P99.99 — місце, де живуть «таємничі сплески». Хвостова затримка важлива для баз даних, брокерів повідомлень і всього, що використовує синхронні комміти.

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

Завдання 10: Переконайтеся, що ви не обмежені CPU під час «дискових» тестів

cr0x@server:~$ mpstat -P ALL 1 5
Linux 6.12.0-amd64 (server) 	12/29/2025 	_x86_64_	(32 CPU)

11:16:01 AM  CPU  %usr %nice %sys %iowait %irq %soft %steal %idle
11:16:02 AM  all  18.2  0.0  31.5    0.3  0.0   9.2    0.0  40.8
11:16:02 AM    7  11.0  0.0  72.0    0.0  0.0  12.0    0.0   5.0

Що це означає: Якщо один або два CPU завантажені високим %sys/%soft, а інші простоюють, можливо, ви обмежені на одній черзі IRQ або шляху обробки завершень.

Рішення: Дослідіть аффініті IRQ та розподіл мультишлюзів перед тим, як купувати «швидші диски» для вирішення проблеми планування CPU.

Завдання 11: Спостерігайте реальне завантаження диска та затримку під час запуску fio

cr0x@server:~$ iostat -x 1 5
Linux 6.12.0-amd64 (server) 	12/29/2025 	_x86_64_	(32 CPU)

Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   w_await wareq-sz  aqu-sz  %util
nvme0n1       98000.0 392000.0     0.0    0.0    0.11     4.00     0.0      0.0     0.00     0.00    12.1   98.5

Що це означає: r_await — груба міра затримки. %util поблизу 100% вказує на насичення пристрою (але на NVMe це може бути хитро; все одно корисно).

Рішення: Якщо fio стверджує про високі IOPS, але iostat показує низьке використання — щось не так (кеш, неправильна ціль або fio не робить те, що ви думаєте).

Завдання 12: Перегляньте журнал помилок NVMe та деталі прошивки (тихі проблеми бувають)

cr0x@server:~$ sudo nvme id-ctrl /dev/nvme0n1 | grep -E 'mn|fr|oacs|oncs'
mn      : SAMSUNG MZVL21T0
fr      : 3B2QGXA7
oacs    : 0x17
oncs    : 0x5f
cr0x@server:~$ sudo nvme error-log /dev/nvme0n1 | head
Error Log Entries for device:nvme0n1 entries:64
 Entry[ 0]
 .................

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

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

Завдання 13: Попереднє кондиціювання / steady-state тест для SSD (щоб не тестувати «вітринну» модель)

cr0x@server:~$ fio --name=precondition --filename=/dev/nvme0n1 --rw=write --bs=1M --direct=1 --ioengine=io_uring --iodepth=32 --numjobs=1 --runtime=600 --time_based --group_reporting
precondition: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=io_uring, iodepth=32
fio-3.38
Starting 1 process
Jobs: 1 (f=1): [W(1)][100.0%][w=1450MiB/s][w=1450 IOPS][eta 00m:00s]

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

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

Завдання 14: Перевірте поведінку TRIM/discard (особливо для віртуальних дисків і thin provisioning)

cr0x@server:~$ lsblk -D -o NAME,DISC-GRAN,DISC-MAX,DISC-ZERO
NAME      DISC-GRAN DISC-MAX DISC-ZERO
sda              2M       2G         0
nvme0n1          4K       2G         0

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

Рішення: Якщо ви покладаєтеся на thin provisioning або тривалу продуктивність SSD, переконайтеся, що стратегія discard/TRIM є свідомою (періодичний fstrim vs online discard).

Проєктування fio-завдань, які нагадують ваше навантаження

Найшвидший шлях ввести себе в оману — використовувати будь-яку fio-команду з блогу, яка не згадує fsync, процентилі або наскільки великий тестовий файл відносно ОЗП.

Визначте сферу: блочний пристрій vs файлова система

  • Блочні тести (--filename=/dev/nvme0n1) — для характеристик медіа/контролера та накладних витрат шляху ОС I/O. Вони обходять метадані файлової системи та фрагментацію. Чудово для порівняння пристроїв; менш передбачувально для «додатка на ext4».
  • Файлові тести (--filename=/data/fio.test) — включають поведінку файлової системи. Добре для опцій монтування, ефектів журналювання та реального розподілу файлів. Але їх легше випадково закешувати.

Керуйте кешуванням явно

Для більшості характеристик сховища:

  • Використовуйте --direct=1.
  • Використовуйте розмір тесту, що не «занадто малий, щоб залишатися теплим». Якщо ви робите файлові тести — обирайте розміри більші за ОЗП при тестуванні читань.
  • Записуйте, чи запускали ви на вільній системі або на спільному вузлі. «Чужий бекап» — це змінна продуктивності.

Оберіть IO-движок з наміром

На Debian 13 зазвичай використовують:

  • io_uring: сучасний, ефективний, підходить для високих IOPS. Може швидше виявити проблеми CPU/IRQ.
  • libaio: класичний асинхронний інтерфейс для O_DIRECT, все ще широко використовується й стабільний.
  • psync: корисний для однопотокової поведінки на зразок sync; не робіть його дефолтом «бо він працює».

Відповідність конкурентності та глибини черги вашому додатку

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

Використовуйте змішані робочі навантаження, якщо реальність змішана

Багато систем роблять 70/30 читань/записів з різними розмірами блоків і семантикою синхронізації. fio це підтримує; ваше завдання — це задекларувати.

Вимірюйте хвіст, а не тільки середнє

Процентилі — це не мода. Це та частина розподілу, де гинуть ваші SLO.

Короткий жарт №2: Якщо ваш звіт бенчмарка містить лише «MB/s», ви не запускали тест — ви влаштували перевірку настрою.

Швидкий план діагностики: знайти вузьке місце без тижня суперечок

Ось послідовність, яку я використовую, коли система «має повільне сховище», а всі вже емоційно прив’язані до теорії.

Перше: доведіть, яким шляхом ви йдете

  1. Підтвердіть пристрій та шари: lsblk, findmnt, перевірте на LVM, mdraid, dm-crypt.
  2. Підтвердіть, що ви влучаєте у потрібну ціль: параметр filename у fio вказує на правильний пристрій або монтування.
  3. Підтвердіть вибір direct vs buffered I/O відповідно до запитання.

Друге: визначте, чи це насичення, чи затримки

  1. Запустіть fio з процентилями і помірною конкурентністю; спостерігайте iostat -x.
  2. Якщо %util високий і затримка росте з іodepth — ви насичуєте пристрій або його шлях чергування.
  3. Якщо використання низьке, але затримка висока — підозрюйте конкуренцію в іншому місці: CPU, IRQ, блокування файлової системи, шифрування або неправильний планувальник.

Третє: відокремте вузькі місця CPU/IRQ від вузьких місць медіа

  1. Перевірте розподіл CPU: mpstat.
  2. Перевірте аффініті IRQ і черги NVMe, якщо заглибилися (тут не повний гайд з тонкого налаштування, але симптом зазвичай «одне ядро в полум’ї»).
  3. Спробуйте інший ioengine або зменшіть iodepth, щоб побачити, чи покращиться хвостова затримка.

Четверте: перевірте поведінку пристрою під тривалим навантаженням

  1. Попередньо кондиціюйте, якщо SSD.
  2. Запускайте довші тести; спостерігайте температуру й пропускну здатність з часом.
  3. Перевіряйте SMART/NVMe журнали на помилки.

П’яте: підтвердіть файлову систему та семантику стійкості

  1. Тестуйте з шаблонами синхронізації, релевантними для додатку (fsync, fdatasync або специфічні шаблони бази даних).
  2. Підтвердіть опції монтування; уникайте «nobarrier»-стилю пасток, якщо у вас немає захисту від втрати живлення і вагомих причин.

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

1) «Читання — 5 GB/s на SATA SSD»

  • Симптом: Буферизовані читання показують багатогігабайтні швидкості; прямі читання значно повільніші.
  • Коренева причина: Кеш сторінок задовольняв читання після прогріву; ви протестували пам’ять.
  • Виправлення: Використовуйте --direct=1, методологію холодного кешу і/або тестуйте розміри, що перевищують ОЗП.

2) «Записи швидкі, але fsync бази повільний»

  • Симптом: Послідовна швидкість запису виглядає чудово; під час синхронних записів виникають стрибки затримки.
  • Коренева причина: Бенчмарк використав асинхронні буферизовані записи; додаток чекає на flush/fua/journal commits.
  • Виправлення: Запускайте fio з семантикою sync: додайте --fsync=1 або використайте --rw=randwrite з релевантними bs і iodepth, та вимірюйте процентилі.

3) «Random write IOPS падає через хвилину»

  • Симптом: Чудові початкові числа; стійка продуктивність сильно падає.
  • Коренева причина: SLC-кеш SSD виснажується і починається збірка сміття; пристрій не був попередньо кондиційований.
  • Виправлення: Попередньо кондиціюйте (тривалі записи), потім тестуйте steady-state; розгляньте overprovisioning або корпоративні SSD для write-heavy навантажень.

4) «Числа бенчмарка змінюються між ідентичними прогоном»

  • Симптом: Та сама команда fio, різні результати щодня.
  • Коренева причина: Фонове навантаження, термічний тротлінг, масштабування частоти CPU, різне розміщення вільного простору або стан кешу.
  • Виправлення: Контролюйте середовище: ізолюйте хост, логувати терміки, фіксуйте частоту CPU за потреби, попередньо кондиціюйте й запускайте кілька ітерацій з фіксацією дисперсії.

5) «Високі IOPS, але жахлива хвостова затримка»

  • Симптом: Чудове середнє; P99.9 — болісне.
  • Коренева причина: Надмірна глибина черги, конкуренція в блочному шарі, піки GC прошивки або спільний пристрій.
  • Виправлення: Зменшіть iodepth, відповідність конкуренції додатку, ізоляція тесту та фокус на процентилях, а не на пікових значеннях.

6) «На сирому пристрої швидко, на файловій системі повільно»

  • Симптом: Тести /dev/nvme чудові; файлові тести на /data — повільні.
  • Коренева причина: Журналювання файлової системи, конкуренція за метадані, мала таблиця інодів, опції монтування або фрагментація.
  • Виправлення: Бенчмаркніть обидва шари свідомо; налаштуйте файлову систему під навантаження; перевірте вирівнювання та вільний простір; розгляньте відмінності XFS/ext4 для паралелізму.

7) «Додавши шифрування, пропускна здатність мало змінилася, але затримки стали дивними»

  • Симптом: Пропускна здатність подібна; хвостова затримка погіршилась.
  • Коренева причина: Шлях шифрування обмежує CPU під сплесками; погана аффініті CPU/NUMA; невеликі накладні витрати на I/O.
  • Виправлення: Виміряйте навантаження CPU під час fio; розгляньте --numjobs і прив’язку CPU; переконайтеся в наявності AES-NI і відповідного режиму шифрування; тримайте реалістичний iodepth.

Три короткі історії з корпоративного фронту сховищ

Коротка історія 1: Інцидент, спричинений хибним припущенням

Середня SaaS-компанія оновила флот вузлів баз даних. Нові NVMe-диски, нове ядро, свіжі Debian-інсталяції. Внутрішній лист бенчмарків виглядав фантастично: випадкові читання — сотні тисяч IOPS. План міграції підписали і запланували на тихий вікенд.

Після перемикання база була «нормальною» кілька годин. Потім під час планового обслуговування: перестроювання індексів, autovacuum і хвиля фонових записів — затримки зросли. Додаток не впав. Він просто став тактовно нефункціональним. Заявки підтримки почали надходити хвилями, як це буває, коли система жива, але страждає.

Хибне припущення було тонким: бенчмарк використовував файлові тести на порожній файловій системі з буферизованим ввід-виводом, і розмір тесту був достатньо малий, щоб кеш сторінок зіграв роль героя. У продакшні датасет бази перевищував пам’ять і змушував робити реальні читання. Гірше — навантаження вимагало частих fsync-подібних операцій; бенчмарк цього не врахував.

Виправлення не полягало в «покупці швидших NVMe». Вони перезапустили тести з --direct=1, реалістичною конкурентністю й процентилями затримки; потім налаштували ліміти I/O конкурування в базі, щоб відповідати поведінці пристрою. Коли вони перестали ганятись за заголовковими IOPS і почали орієнтуватися на P99 при реалістичному iodepth — система стабілізувалася. Диски були в порядку. Наратив бенчмарка — ні.

Коротка історія 2: Оптимізація, що відбилась боком

Інша організація мала великий аналітичний кластер. Хтось помітив, що нічні джоби стали повільніші після оновлення сховища, незважаючи на кращий апарат. Доброзичливий інженер вирішив, що вузьке місце — «накладні витрати файлової системи», тож вони перевели деякі робочі навантаження на сирі блочні пристрої і «підкрутили» черги на рівні додатка, як у fio.

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

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

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

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

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

Одного кварталу з’явилася регресія затримки після рутинного оновлення. Команда мала інстинкти, але не було явного курця. Хтось звинувачував ядро. Інші — новий конвеєр пакетної обробки. Декілька пропонували відкотити все назад і все.

Оскільки бенчмарки були відтворювані й записані, вони швидко помітили невелику, але значущу зміну: вибір планувальника відрізнявся між двома образами хостів, і у постраждалих вузлів була інша картина розподілу IRQ. Сирий пристрій не «сповільнився», але шлях CPU став шумнішим, і хвостова затримка погіршилася під тим же профілем fio.

Виправлення було нудним: стандартизувати вибір планувальника для цього класу пристроїв, застосувати послідовну політику аффініті IRQ, знову запустити той самий набір fio як пропускну перевірку, і тільки потім рухатись далі. Жодних героїчних трюків, жодних опівнічних дзвінків вендорам. Рятівний крок — не тонке налаштування; це дисципліноване порівняння.

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

Покроковий план: бенчмарк, який ви зможете обґрунтувати у постмортемі

  1. Запишіть мету навантаження. «Нам потрібна передбачувана P99.9 затримка для 4k випадкових читань при конкурентності X» — корисно. «Нам потрібні швидкі диски» — ні.
  2. Задокументуйте середовище. Версія Debian, ядро, версія fio, модель/прошивка пристрою, файлова система, опції монтування, планувальник.
  3. Оберіть сферу тесту. Сирий пристрій vs файлова система. Якщо файлова система — зафіксуйте вільний простір і ризик фрагментації.
  4. Керуйте кешем. Для характеристики пристрою використовуйте --direct=1. Якщо буферизований ввід-вивід — обґрунтуйте це і доведіть стан кешу.
  5. Попередньо кондиціюйте, якщо SSD і важливий steady-state. Не пропускайте, якщо у продакшні багато записів.
  6. Використовуйте кілька тривалостей. Короткі 30с для санітарної перевірки, 10–30 хв для стійкої поведінки.
  7. Вимірюйте процентилі. Завжди. Якщо вас не цікавить хвостова затримка — або вам пощастило, або у вас пакетна система, якою ніхто не цікавиться.
  8. Запускайте з реалістичною конкурентністю. Почніть із того, що додаток може згенерувати, потім дослідіть більше, щоб побачити запас і критичні точки.
  9. Спостерігайте систему під час прогону. iostat -x, mpstat, температури пристроїв.
  10. Повторюйте і повідомляйте дисперсію. Якщо результати сильно варіюються — у вас не бенчмарк, а загадка.
  11. Приймайте рішення, прив’язане до метрики. Наприклад: «Приймаємо, якщо P99.9 < 2ms при iodepth=8, numjobs=4.»

Короткий чекліст: «Чи я тестую те, що треба?»

  • Я явно обрав прямий чи буферизований ввід-вивід?
  • Чи мій розмір тесту значущий відносно ОЗП?
  • Чи я записав налаштування кешу та семантику стійкості?
  • Чи зібрав я процентилі затримки?
  • Чи відповідні розміри блоків та конкурентність продакшну?
  • Чи перевірив я терміки та насичення CPU?

Часті питання

1) Чи завжди треба використовувати --direct=1 на Debian 13?

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

2) Чи завжди io_uring кращий за libaio?

Ні. io_uring часто швидший і більш масштабований, але може виявляти вузькі місця CPU/IRQ і чутливий до особливостей ядра/пристрою. Використовуйте обидва під час діагностики; стандартизуйте один для регресійного тестування, щоб результати були порівнянними.

3) Чому мої числа fio відмінні, але база повільна?

Типові причини: fio тестував послідовний I/O, а база — випадковий; fio не включав семантику sync/flush; fio використовував іншу глибину черги, ніж база; накладні витрати файлової системи і журналювання не були представлені; або база обмежена CPU-локами, а не I/O.

4) Який розмір блоку тестувати?

Тестуйте кілька розмірів, але починайте з того, що використовує ваш додаток: 4k випадкові читання — класична база; 16k/32k можуть мати значення для деяких баз; 128k–1M для послідовних сканів і бекапів. Якщо оберете лише один — випадково оптимізуєте під нього.

5) Якої тривалості мають бути прогони fio?

Достатньо довго, щоб охопити потрібну поведінку. Для сплеску: 30–60 секунд підходить. Для steady-state SSD і хвостової затримки: хвилини або десятки хвилин, після попереднього кондиціювання, якщо ви багато пишете в продакшні.

6) Як уникнути видалення даних при тестуванні сирих пристроїв?

Припускайте, що fio може зруйнувати ваш день. Використовуйте виділений тестовий пристрій або одноразовий LVM LV. Тричі перевіряйте --filename. Для недеструктивних тестів використовуйте --rw=read, а записні тести вважайте деструктивними, якщо тільки ви не орієнтуєтеся на тестовий файл у змонтованій файловій системі.

7) Чому «QD32» така поширена за замовчуванням у прикладах?

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

8) Чи потрібно скидати кеші між прогоном?

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

9) Мої результати fio відрізняються між файловим і блочним тестом. Що «реальне»?

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

10) Яке поле виводу fio найкорисніше?

Процентилі затримки (clat percentiles) при реалістичній конкурентності. Пропускна здатність — відносна; хвостова затримка — місце, де живе користувацький біль.

Висновок: наступні кроки, які реально знижують ризик

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

Конкретні наступні кроки:

  1. Оберіть два-три профілі fio, що відповідають виробничим формам I/O (4k випадкове читання, змішане 70/30, синхронний записовий шаблон, якщо релевантно).
  2. Стандартизувати фіксацію середовища (пристрій, прошивка, ядро, планувальник, файлова система, опції монтування, direct/buffered).
  3. Зробіть просту проходну/непроходну перевірку на основі P99/P99.9, а не пікових MB/s.
  4. Запускайте precondition + steady-state тести для SSD-підтримуваних систем з інтенсивними записами.
  5. Коли результати дивують — дотримуйтеся швидкого плану діагностики замість «налаштування, поки графік не стане гарним».

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

← Попередня
Flash: технологія, яка була всюди — поки не зникла
Наступна →
Ubuntu 24.04: sudo працює повільно — виправлення DNS/hostname, що усувають затримку (випадок №6)

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