Ви запустили fio, отримали захопливе число, відправили його в закупівлі, а шість тижнів потому в продакшні все ніби іде у сиропі.
Тепер усі дивляться на «сховище», ніби воно — свідомий лиходій.
Синтетичні бенчмарки не просто не змогли передбачити реальність — вони переконали вас у протилежному.
Це не невдача долі. Це режим відмови. І ви можете навчитися помічати це швидко, перш ніж це відправлять у продакшн.
Що таке синтетичні бенчмарки (і які припущення вони мовчки роблять)
Синтетичний бенчмарк — це спроектоване навантаження: ви обираєте суміш читань/записів, розмір блоку, глибину черги, кількість потоків, випадковість, тривалість і розмір набору даних.
Це лабораторний щур. Корисний. Але це не ваші користувачі.
Брехня не в тому, що синтетичні інструменти «помилкові». Брехня в тому, що вони за замовчуванням неповні, а люди трактують вихід як наказ до купівлі.
Продуктивність сховища — це властивість системи: апаратне забезпечення, мікропрограма, ядро, файловий система, драйвери, multipath, мережа, віртуалізація і галасливий сусід, про якого ви не знали.
Контракт бенчмарка, який ви не прочитали
Кожен синтетичний результат супроводжується невисловленими припущеннями. Коли ви запускаєте «4k randread QD=64», ви стверджуєте:
- Ваше реальне навантаження читає шматками по 4k (або принаймні поводиться схоже на рівні IO).
- Ваше навантаження може підтримувати queue depth 64 без затримок вище по стеках.
- Ваш додаток терпить ту ж розподіл латентності, а не просто те саме середнє значення.
- Ваші кеші (page cache, кеш контролера, CDN, кеш додатку) поводяться подібно.
- Шлях IO однаковий: та сама файлова система, ті самі опції монтування, та сама шифрація/компресія, ті самі налаштування реплікації.
У продакшні ці припущення знищуються реальністю. Бенчмарк все ще друкує чисте число. Ось у чому небезпека.
Ось ментальна модель, що тримає вас чесними: бенчмарки не вимірюють «швидкість диска». Вони вимірюють конвеєр за дуже специфічних умов.
Змініть умови — зміниться історія.
Жарт №1: Синтетичні бенчмарки як резюме — усі виглядають чудово, поки ви не перевірите рекомендації і не дізнаєтесь, що «експерт з Kubernetes» означав «одноразово відкрив дашборд».
Як синтетичні бенчмарки брешуть: типові механізми
Бенчмарки «брешуть» у передбачуваних випадках. Якщо ви вивчите патерни, зможете виявляти їх рано — інколи просто глянувши на графік і задавши одне грубе питання.
1) Кеш, кеш і ще раз кеш (і бенчмарк, який ніколи не торкнувся диска)
Класика: ваш бенчмарк читає одні й ті самі дані повторно, і OS page cache віддає їх з оперативної пам’яті.
Або кеш контролера RAID поглинає записи й пізніше повільно скидає їх на диск, поки бенчмарк святкує.
Реальні навантаження рідко отримують нескінченний розігрітий кеш. Вони мають часткову локальність, шторми витіснення і «було швидко до 09:03».
Бенчмарки, які не розмірюють набір даних поза кешем, просто вимірюють пропускну здатність пам’яті з додатковими кроками.
2) Фантазії про глибину черги: QD=64 — це не «реалістичніше», це «інша реальність»
Велика глибина черги підвищує пропускну здатність на пристроях, які можуть реупорядкувати і паралелізувати внутрішні операції. NVMe це любить. SATA — терпить. Мережі інколи вдають.
Але додатки можуть ніколи не генерувати такої конкуренції, бо вони блокуються на локах, межах комітів, RPC-колах або CPU.
Якщо ваш додаток одно-потоковий або серіалізований через WAL fsync бази даних, результати QD=64 — це тривіальність.
Ви повинні бенчмаркувати на глибині черги, які вашу систему може підтримувати end-to-end.
3) Театр розміру блоку: «IOPS» без розміру блоку — беззмістовно
1M послідовний пропуск і 4k випадкові IOPS — це різні види спорту. Система може блискуче справлятись з одним і жалюгідно з іншим.
Деякі вендори люблять показувати ту метрику, яка їх краще висвітлює. Так само роблять інженери, якщо бути відвертими.
Якщо ваше навантаження — «багато дрібних читань метаданих», а ви бенчмаркуєте «128k послідовних читань», ви не бенчмаркували навантаження. Ви бенчмаркували надії.
4) Середні значення латентності — це вигадка про продуктивність
Середні приховують те, що викликає виклики в on-call: хвостову латентність (p95, p99, p99.9) і сплески латентності.
Багато синтетичних тестів віддають середнє, яке виглядає нормально, тоді як p99 — справжній жах.
Що важливо — залежить від системи. Для систем з чергуванням p99 може спричиняти повторні спроби, тайм-аути й каскадні відмови.
Для бази даних кілька довгих fsync можуть блокувати коміти і створювати «thundering herd».
5) «Direct IO» vs buffered IO: обравши неправильно, виміряєте іншу підсистему
Buffered IO включає поведінку page cache, writeback і пороги dirty page. Direct IO обходить page cache і змінює вимоги до вирівнювання.
Продакшн часто змішаний: бази даних використовують direct IO для файлів даних, але покладаються на buffered IO в інших місцях; сервіси можуть ненавмисно кешувати читання.
Якщо ви бенчмаркуєте з --direct=1, а ваше навантаження переважно буферизовані читання — ви недооціните ефект кешування. Якщо бенчмаркуєте буферизовано, але очікуєте direct семантики — ви перенесете обіцянки.
Обирайте режим IO, що відповідає реальному шляху вашого додатку, а не вподобанням тестувальника.
6) Файлова система та опції монтування: невидимий множник
Ext4 з data=ordered поводиться інакше, ніж XFS під тиском метаданих. ZFS має свій всесвіт (ARC, recordsize, sync-поведінка).
Опції монтування як noatime можуть прибрати метадані-записи. Параметри як бар’єри, режим журналювання і discard можуть змістити латентність.
Синтетичні тести запускаються на порожній файловій системі з ідеальною локальністю. Продакшн — фрагментований, має мільйони інодів і працює під конкурентним навантаженням.
7) Стан пристрою має значення: SSD з коробки — теж брехуни
Багато SSD показують вищу продуктивність коли вони порожні через SLC-кешування і чисту флеш. Під стійким випадковим записом вмикаються garbage collection і wear leveling.
«Швидкий тест» може показати фантазію, що розвалиться через години або дні реального навантаження.
8) Компактація, контрольні суми, шифрування, реплікація: реальна робота коштує циклів
Стек сховища часто виконує додаткову роботу: контрольні суми, стиснення, шифрування в стані спокою, дедуплікацію, реплікацію, erasure coding, снапшоти.
Синтетичні бенчмарки, які не вмикають ті самі можливості, не бенчмаркують вашу систему. Вони бенчмаркують іншу.
9) Віртуалізація і сусіди: ви тестували хост; продакшн — це багатоквартирний будинок
На спільній інфраструктурі ви не володієте контролером, кешем, uplink мережі чи розкладом «хтось робить резервне копіювання».
Ваш бенчмарк може запускатися вночі, наодинці. Продакшн працює опівдні, з тисячею сусідів.
10) Бенчмарк стає навантаженням (і все підлаштовується під нього)
Інженери налаштовують sysctl і планувальники IO, поки fio не виглядає чудово, потім відправляють у продакшн. Бенчмарк стає тестом прийнятності.
Система тепер оптимізована під синтетичний візерунок, іноді за рахунок змішаних навантажень або латентності.
Жарт №2: Якщо ви налаштували систему до ідеалу бенчмарка, вітаю — ви успішно привчили своє сховище складати стандартизований тест.
Цікаві факти та історія (так, це важливо)
- IOPS стали популярними через те, що HDD погано справлялися з випадковими IO. Ранні обговорення в ентерпрайзі зводилися до «скільки 4k випадкових читань», бо шпинделі були вузьким місцем.
- Середню латентність історично повідомляли, бо це було просто. Хвостова латентність стала мейнстрімом пізніше, коли великі розподілені системи зробили p99-стрибки проблемою надійності.
- Кеш запису RAID-контролера може робити малі записи надприродними. Це часто батарейно-підтримуваний DRAM-кеш — швидкий, поки його не треба скидати на диски.
- SSD мають «короткі режимні сплески» (наприклад, SLC-кешування), які спотворюють короткі тести. Багато пристроїв спроектовані так, щоб виглядати добре у коротких тестах і споживчих слідах.
- Page cache Linux може задовольнити читання без торкання сховища взагалі. Якщо не використовувати direct IO або не задати достатньо великий набір даних, ви бенчмаркуєте RAM.
- Планувальники IO еволюціонували, бо різні носії потребували різного чергування. Те, що допомагало ротаційним дискам (реупорядкування пошуків), може бути марним або шкідливим на NVMe.
- «fsync() робить це реальним» — правда лише частково. Пристрої й контролери можуть підтверджувати записи до їхнього збереження, якщо бар’єри, налаштування кеша і захист від відключення живлення не узгоджені.
- Хмарні диски часто рекламують пропускну здатність/IOPS окремо від латентності. Ви можете досягти цілей по IOPS і при цьому провалити SLO, бо користувачі відчувають хвостову латентність.
- Деякі набори бенчмарків стали інструментом закупівель. Коли число визначає покупку, вендори оптимізуються під нього, іноді без покращення реальних навантажень.
Корисна перефразована ідея від W. Edwards Deming: коли метрика стає ціллю, вона перестає бути доброю метрикою. Версія для сховища проста:
якщо «fio IOPS» — ваша мета, ви отримаєте fio IOPS — незалежно від того, чи база даних припинить таймаутитись.
Три міні-історії з корпоративного світу
Міні-історія №1: Інцидент, спричинений неправильним припущенням
Середня SaaS-компанія мігрувала з локальних NVMe на мережеву платформу блочного зберігання.
План міграції затвердили, бо синтетичний тест показав «схожі IOPS» і «вищу пропускну здатність». Слайд-дек був бездоганний.
Першого тижня після відключення латентність клієнтських запитів щодня різко зростала. Не повний збій, а поступове гальмування: таймаути, повторні спроби і зростаючий беклог черг.
Команда on-call дивилась на CPU і пам’ять — все в нормі. Мережа? В нормі. Дашборд сховища показував IOPS нижче рекламованого ліміту.
«Отже, це не сховище», — сказав хтось, і ця фраза закінчила чимало чужих кар’єр.
Вони припустили, що ємність по IOPS гарантує стабільність латентності.
Прихована різниця була у fsync-інтенсивних записах. Додаток використовував базу даних зі строгими гарантіями збереження при коміті.
Синтетичний бенчмарк переважно робив випадкові читання з великою глибиною черги і великими батчами. Продакшн — багато дрібних синхронних записів з помірною конкуренцією.
Під ранковим навантаженням хвостова латентність сховища зростала, а латентність комітів перетворювалась у латентність запитів.
Виправлення полягало не в «більше IOPS». Воно полягало у вирівнюванні навантажень: виміряти латентність синхронних записів при тій конкуренції, яку реально дає база.
Вони врешті змінили тип тому і тонко налаштували параметри комітів бази даних, і перестали затверджувати зміни сховища на основі одного профілю fio.
Урок був болісно простий: не можна робити висновки з неправильного бенчмарка.
Інциденти зі сховищем часто спричинені невідповідністю між виміряними умовами і умовами продакшну, а не тим, що компонент «став повільнішим».
Міні-історія №2: Оптимізація, яка обернулася проти
Команда платформ обробки даних мала нічне пакетне навантаження. Вони гордилися дисципліною бенчмаркінгу: кожен новий тип вузла проходив однаковий синтетичний набір.
Один інженер помітив, що зміна планувальника IO і збільшення глибини черги підняли числа бенчмарка.
Вони розгорнули налаштування по всьому кластеру і оголосили перемогу.
Через два тижні денні інтерактивні запити почали показувати джиттер.
Нічого катастрофічного, але хвостова латентність стала робити дашборди «липкими», і на on-call з’явилося невдоволення.
Налаштування оптимізувало пропуск під високою конкуренцією, але змінило справедливість при змішаних навантаженнях.
Справжня проблема була у конкуренції: планувальник і налаштування черги дозволяли пакетному IO захоплювати час пристрою.
Синтетичні тести не включали конкурентне латентнісно-чутливе навантаження, тож вони ніколи не виявили зірваність.
Продакшн виявив.
Відкат налаштувань одразу покращив p99 запитів, хоча пропускність пакетів трохи впала.
Команда навчилася бенчмаркувати «змішані режими»: один джоб тисне пропуск, а інший вимірює латентність.
Вони також зрозуміли, що налаштування, яке робить бенчмарк гарнішим, може бути податком на користувацький досвід.
Міні-історія №3: Нудна, але правильна практика, що врятувала ситуацію
Команда фінансових сервісів керувала платформою зі строгим контролем змін. Вони не блищали.
Перед будь-яким оновленням вони знімали базову лінію: версії прошивки пристроїв, налаштування черг, опції монтування файлових систем і невеликий набір тестів, що репрезентують навантаження.
Вони зберігали результати з часовими мітками і версіями ядра. Це було нудно. Але це була машина часу.
Після планового оновлення ядра вони помітили тонке збільшення p99 латентності записів. Користувачі майже не відчували — допоки не настав кінець місяця.
Оскільки у них були базові показники, вони могли сказати «це відхилення почалося саме після оновлення», а не «сховище останнім часом якось дивне».
Це звузило пошук до змін в IO-стаку, а не до туманного «можливо апарат ламається».
Вони використали свої fio джоби бази плюс метрики на рівні додатку, щоб підтвердити регресію.
Потім порівняли налаштування блочного шару і виявили, що за замовчуванням змінились поведінка чергування і вибір планувальника в новому ядрі.
Вони зафіксували попередню поведінку і запланували контрольоване повторне тестування нових дефолтів.
Кінець місяця пройшов без драм. Ніхто не святкував. Ось у чому суть.
Практика, що врятувала їх, не була магічним бенчмарком; це було повторюване вимірювання, атрибуція змін і відмова «налаштовувати навмання».
Плейбук швидкої діагностики: що перевірити першим/другим/третім
Коли «сховище повільне», потрібна швидка воронка. Не тижневий проект бенчмарків. Ось порядок, що зазвичай швидко знаходить істину.
Перше: доведіть, чи це латентність, пропуск чи насичення
- Подивіться хвостову латентність (p95/p99), а не лише середнє.
- Перевірте завантаження: чи пристрій на 100% зайнятий? Чи черга зростає?
- Корелюйте з навантаженням: чи змінювалась конкуренція? Чи почався бекап? Чи запустилась компактація?
Друге: локалізуйте шар вузького місця
- Додаток: локи, паузи GC, вичерпання пулу з’єднань, частота fsync.
- Файлова система: тиск журналу, шторми метаданих, фрагментація, опції монтування.
- Блочний шар: глибина черги, планувальник, поведінка злиття, тротлінг.
- Пристрій: «стех-стан» SSD, причудливості прошивки, термічне тротлінгування.
- Мережа/фабрика зберігання: перевідправлення, затори, flapping multipath.
- Віртуалізація/спільне середовище: «шумний сусід», steal CPU, політики тротлінгу.
Третє: відтворіть безпечно репрезентативний мікротест
- Обирайте тест, що відповідає вашому розміру IO, суміші чит/запис, синхронній поведінці і конкуренції.
- Запустіть поруч з продакшн-навантаженням, якщо можливо (обережно), або відтворіть трасу у клоні стенду.
- Підтвердіть як системними, так і додатковими метриками додатку. Якщо вони не сходяться — довіряйте додатку.
Цей плейбук працює, бо він скептичний: припускає, що симптом може бути зверху, знизу або самовинесений міфами бенчмаркінгу.
Практичні завдання: команди, що означає вивід і яке рішення прийняти
Це завдання, які я фактично виконую, коли хтось дає мені результат бенчмарка або тикет «сховище повільне».
Кожне завдання містить: команду, приклад виводу, що це означає і яке рішення воно дає.
Завдання 1: Ідентифікувати блочні пристрої та їх топологію
cr0x@server:~$ lsblk -o NAME,MODEL,SIZE,ROTA,TYPE,MOUNTPOINTS
NAME MODEL SIZE ROTA TYPE MOUNTPOINTS
nvme0n1 Samsung SSD 1.8T 0 disk
├─nvme0n1p1 512M 0 part /boot
└─nvme0n1p2 1.8T 0 part /
sda ST8000NM0045 7.3T 1 disk
└─sda1 7.3T 1 part /mnt/archive
Значення: ROTA=0 вказує на твердотільний накопичувач; ROTA=1 — на обертовий диск. Модель підказує контролер і клас.
Знати, чи ви на NVMe, SATA чи HDD, змінює уявлення про «хороше» і про те, яка поведінка чергування прийнятна.
Рішення: Оберіть профілі бенчмарків, відповідні класу пристрою. Не використовуйте NVMe-стиль глибину черги на одному HDD і не називайте це «нечесним залізом».
Завдання 2: Перевірити файлову систему та опції монтування (тихі регулятори продуктивності)
cr0x@server:~$ findmnt -no SOURCE,TARGET,FSTYPE,OPTIONS /
/dev/nvme0n1p2 / ext4 rw,relatime,errors=remount-ro
Значення: Опції монтування кажуть, чи ви платите податок за метадані (atime), який режим журналювання у вас і чи ввімкнено discard.
Рішення: Якщо середовище бенчмарка має інші опції монтування, ніж продакшн — зупиніться. Зрівняйте їх і повторіть тест.
Завдання 3: Підтвердити, що ви випадково не бенчмаркуєте RAM через page cache
cr0x@server:~$ grep -E 'MemTotal|MemAvailable|Cached' /proc/meminfo
MemTotal: 263824032 kB
MemAvailable: 221443104 kB
Cached: 78455232 kB
Значення: Велике значення Cached плюс набір даних менший за RAM часто означає, що читання буде з кешу.
Рішення: Зробіть набір даних більшим за RAM (або використайте direct IO). Якщо не можете — чітко вкажіть, що вимірювали кешовану продуктивність, а не диск.
Завдання 4: Перевірити тиск запису і пороги dirty page
cr0x@server:~$ sysctl vm.dirty_background_ratio vm.dirty_ratio
vm.dirty_background_ratio = 10
vm.dirty_ratio = 20
Значення: Ці параметри контролюють, скільки «брудних» даних може накопичуватись перед тим, як writeback змусить тротлінг.
Бенчмарки, що записують буферизовано, можуть виглядати чудово доти, поки ядро не вирішить скинути дані, і тоді настануть сплески латентності.
Рішення: Якщо бачите періодичні стрибки латентності в буферизованих тестах, відтворіть з direct IO або відкоригуйте тривалість тесту і стежте за поведінкою writeback.
Завдання 5: Подивитися, чи пристрій насичений (завантаження і глибина черги)
cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0 (server) 01/12/2026 _x86_64_ (64 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
12.10 0.00 4.20 6.50 0.00 77.20
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
nvme0n1 820.0 52480.0 0.0 0.0 2.10 64.0 610.0 78144.0 0.0 0.0 8.40 128.1 5.10 92.00
Значення: %util близько до 100% свідчить про насичення. aqu-sz показує backlog в черзі. r_await/w_await показують латентність з урахуванням чергування.
Рішення: Якщо насичення — вам потрібні або додаткові пристрої, або краща паралельність, або менше роботи на IO (вибір компресії, батчування, кешування). Якщо не насичено, але латентність висока — перевіряйте прошивку, тротлінг або upstream-затримки.
Завдання 6: Виміряти поведінку IO по процесах (хто фактично вантажить)
cr0x@server:~$ pidstat -d 1 3
Linux 6.5.0 (server) 01/12/2026 _x86_64_ (64 CPU)
# Time UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
12:00:01 999 18422 0.00 41280.00 0.00 45 postgres
12:00:01 0 2211 0.00 5120.00 0.00 6 rsync
Значення: Можна відокремити «сховище повільне» від «один процес робить багато».
iodelay — грубий індикатор часу, витраченого на очікування IO.
Рішення: Якщо фоновий джоб домінує — перенесіть його час або тротлюйте. Якщо основний сервіс чекає — фокусуйтеся на латентності і шляху збереження.
Завдання 7: Підтвердити планувальник IO і налаштування черги (особливо після оновлень ядра)
cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq
Значення: Обраний планувальник вказаний у дужках. NVMe часто ефективно використовує none; інші пристрої можуть отримати вигоду від mq-deadline під змішаним навантаженням.
Рішення: Не налаштовуйте виключно заради показників бенчмарка. Якщо у вас латентно-чутливі навантаження, тестуйте під конкуренцією і обирайте планувальник, що зберігає хвостову латентність.
Завдання 8: Побачити тротлінг або помилки пристрою в логах ядра
cr0x@server:~$ dmesg -T | tail -n 12
[Mon Jan 12 11:58:10 2026] nvme nvme0: failed command: WRITE, cmdid 123 qid 4
[Mon Jan 12 11:58:10 2026] nvme nvme0: status: { DNR }
[Mon Jan 12 11:58:11 2026] EXT4-fs (nvme0n1p2): warning: mounting fs with errors, running e2fsck is recommended
Значення: Числа бенчмарка не мають значення, якщо пристрій помиляється або файлова система пошкоджена.
Стрибки латентності можуть бути результатом повторних спроб, скидань або деградованих режимів.
Рішення: Зупиніть тестування продуктивності. Стабілізуйте систему: перевірте SMART/NVMe логи, кабелі/контролер і вирішіть помилки файлової системи.
Завдання 9: Запустити fio-тест, орієнтований на латентність з direct IO (чесніше для багатьох шляхів БД)
cr0x@server:~$ fio --name=lat4k --filename=/mnt/testfile --size=8G --direct=1 --rw=randread --bs=4k --iodepth=4 --numjobs=4 --time_based --runtime=60 --group_reporting
lat4k: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=4
...
read: IOPS=42000, BW=164MiB/s (172MB/s)(9840MiB/60001msec)
slat (nsec): min=1800, max=21000, avg=5400.10, stdev=1100.30
clat (usec): min=45, max=9200, avg=90.20, stdev=40.10
lat (usec): min=49, max=9210, avg=96.10, stdev=40.50
clat percentiles (usec):
| 1.00th=[ 55], 5.00th=[ 62], 10.00th=[ 68], 50.00th=[ 84]
| 90.00th=[ 112], 95.00th=[ 135], 99.00th=[ 240], 99.90th=[ 1200]
Значення: IOPS в нормі, але перцентилі розповідають реальну історію. p99.9 = 1.2ms може бути прийнятним — або порушити SLO, якщо ваш шлях запиту сумує кілька IO.
Рішення: Якщо хвостова латентність висока — зменшіть конкуренцію, знизьте глибину черги, перевірте GC/тротлінг або перейдіть на клас пристроїв з кращою стійкою латентністю.
Завдання 10: Тестувати послідовну пропускну здатність з реалістичним розміром блоку і конкуренцією
cr0x@server:~$ fio --name=seqread --filename=/mnt/testfile --size=16G --direct=1 --rw=read --bs=1M --iodepth=8 --numjobs=2 --time_based --runtime=60 --group_reporting
seqread: (g=0): rw=read, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=libaio, iodepth=8
...
read: IOPS=980, BW=980MiB/s (1027MB/s)(58800MiB/60001msec)
Значення: Добре для великих сканувань, бекапів, реплікації логів. Але це не прогнозує продуктивність для дрібних випадкових IO.
Рішення: Використовуйте це для планування ємності для масових операцій і вікон обслуговування, а не як аргумент для SLO бази даних щодо латентності.
Завдання 11: Перевірити налаштування discard/TRIM (можуть створювати стрибки латентності)
cr0x@server:~$ findmnt -no TARGET,OPTIONS /mnt/test
/mnt/test rw,relatime,discard
Значення: Постійний discard може додавати накладні витрати на деяких пристроях. Деякі середовища віддають перевагу періодичному fstrim.
Рішення: Якщо бачите періодичні сплески латентності, синхронізовані з дискарами, переключіться на запланований trim і повторно протестуйте.
Завдання 12: Перевірити NVMe SMART і стан носія (стійкий стан має значення)
cr0x@server:~$ sudo nvme smart-log /dev/nvme0
Smart Log for NVME device:nvme0 namespace-id:ffffffff
critical_warning : 0x00
temperature : 47 C
available_spare : 100%
percentage_used : 3%
data_units_read : 12,345,678
data_units_written : 9,876,543
media_errors : 0
num_err_log_entries : 0
Значення: Температура і лічильники помилок можуть пояснити тротлінг і повторні спроби. percentage_used дає грубу індикацію зносу.
Рішення: Якщо температура висока або з’являються помилки — виправте апарат/повітряний потік до того, як звинуватите навантаження або «погане налаштування».
Завдання 13: Перевірити, чи ваш «випадковий» тест не звертається до тих самих блоків (перевірка локальності)
cr0x@server:~$ fio --name=randcheck --filename=/mnt/testfile --size=64G --direct=1 --rw=randread --bs=4k --iodepth=1 --numjobs=1 --runtime=30 --time_based --group_reporting --randrepeat=0
randcheck: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
...
read: IOPS=8200, BW=32.0MiB/s (33.6MB/s)(960MiB/30001msec)
Значення: --randrepeat=0 уникає повторення тієї самої випадкової послідовності між прогоном. Більший --size допомагає подолати кеш.
Рішення: Якщо продуктивність падає при розширенні набору даних, попередній результат був, ймовірно, завищений кешем.
Завдання 14: Підтвердити семантику збереження (налаштування кешу запису на рівні пристрою)
cr0x@server:~$ sudo hdparm -W /dev/sda
/dev/sda:
write-caching = 1 (on)
Значення: Кеш запису може покращити швидкість, але змінює довговічність, якщо немає захисту від відключення живлення і відповідних бар’єрів.
Рішення: Для систем із суворою довговічністю переконайтеся, що стек налаштований правильно, і бенчмаркуйте з fsync/синхронними шаблонами — інакше ви вимірюєте «підтверджені» записи, а не персистентні.
Завдання 15: Виміряти латентність на рівні файлів з точки зору файлової системи
cr0x@server:~$ strace -T -e trace=fsync -p 18422 -s 0
strace: Process 18422 attached
fsync(57) = 0 <0.012341>
fsync(57) = 0 <0.089120>
fsync(57) = 0 <0.007882>
Значення: Ці таймінги — реальність додатку. Якщо fsync іноді займає 90ms, ваш «середній 1ms латентності» звіт про сховище не має значення.
Рішення: Якщо латентність fsync стрибкоподібна — шукайте шторми writeback, GC пристрою, конкуренцію або проблеми на шляху довговічності (бар’єри, скидання кеша, мережеве зберігання).
Типові помилки: симптом → корінна причина → виправлення
1) Симптом: «Бенчмарк каже 500k IOPS, але додаток таймаутиться»
Корінна причина: Глибина черги і конкуренція в бенчмарку перевищують те, що додаток може підтримувати; хвостова латентність — справжній обмежувач.
Виправлення: Бенчмаркуйте з реальною конкуренцією (thread-ами, iodepth). Відслідковуйте p95/p99. Підтверджуйте таймінги на рівні додатку (fsync, латентність запитів).
2) Симптом: «Читання шалено швидкі, потім раптово повільні через кілька хвилин»
Корінна причина: Розігрів page cache або кеш контролера; набір даних занадто малий або повторюваний.
Виправлення: Використовуйте direct IO або набір даних більший за RAM; вимкніть randrepeat; запускайте довші тести і стежте за частками хітів кешу де можливо.
3) Симптом: «Записи виглядають чудово в 30-сек тесті, жахливо через годину»
Корінна причина: SLC-кеш SSD / короткочасне буферування приховують steady-state garbage collection і write amplification.
Виправлення: Попередньо підготуйте пристрій (заповніть і тримайте записи), запускайте тривалі час-орієнтовані тести і вимірюйте steady-state перцентилі латентності.
4) Симптом: «Пропускність висока, але інтерактивна латентність жахлива під час пакетних задач»
Корінна причина: Проблеми справедливості/пріоритетів: планувальник, чергування або відсутність ізоляції IO. Пакетне навантаження домінує в часі пристрою.
Виправлення: Тестуйте змішані навантаження; застосуйте cgroup IO-контроль або розклад задач; оберіть планувальник для справедливості латентності, а не максимуму пропуску.
5) Симптом: «Той самий бенчмарк на двох “ідентичних” вузлах сильно відрізняється»
Корінна причина: Відмінності у прошивці, ширині/швидкості PCIe, термічний тротлінг, фонові сканування або стан файлової системи.
Виправлення: Інвентаризуйте прошивки/налаштування ядра; перевірте швидкість/ширину лінку; дивіться температуру; підтвердіть фонові задачі; узгодьте опції файлової системи/монтування.
6) Симптом: «Випадкові записи IOPS в нормі, але fsync повільний»
Корінна причина: Бенчмарк не робить синхронних записів; шлях довговічності (скид кеша, бар’єри, журнал) — вузьке місце.
Виправлення: Використовуйте fio з --fsync=1 або синхронні механізми; вимірюйте fsync безпосередньо в додатку; перевірте кеш запису контролера і наявність захисту від відключення живлення.
7) Симптом: «Сховище виглядає простаючим, але латентність висока»
Корінна причина: Затримки вгору по стеку (локи, тротлінг CPU, мережеві повторні передачі) або переривчасті скидання/повторні спроби пристрою.
Виправлення: Корелюйте причини очікування додатку; перевірте dmesg; підтвердіть мережеві статистики, якщо віддалено; інспектуйте per-process IO wait і steal CPU.
Контрольні списки / поетапний план для чесного бенчмаркінгу
План крок за кроком: від «красивих чисел» до «рішеньного рівня результатів»
- Запишіть питання. Ви обираєте залізо? Перевіряєте міграцію? Діагностуєте регресію латентності? Різні питання вимагають різних тестів.
- Витягніть характеристики навантаження. Розподіл розмірів IO, суміш чит/запис, синхронна поведінка, конкуренція, робочий набір, сплески і прийнятна хвостова латентність.
- Зіставте стек. Та сама файлова система, опції монтування, шифрування/компресія, реплікація, ядро та драйвери як у продакшні. Жодного «майже так само».
- Визначте, що будете звітувати. Завжди вказуйте розмір блоку, глибину черги, numjobs, direct vs buffered, тривалість, розмір набору даних і перцентилі.
- Переможіть фальшиву швидкість. Набір даних більший за кеші,
--randrepeat=0, запускайте довго, щоб досягти steady state, і уникайте «хвалитися першими 10 секундами». - Вимірюйте і системні, і додатні сигнали. iostat/pidstat/гістограми латентності плюс латентність запитів додатку і кількість помилок.
- Тестуйте змішані навантаження. Один джоб на пропуск, плюс один зонд на латентність. Продакшн — не один fio, що працює вночі на порожньому томі.
- Запускайте мінімум три рази. Якщо результати дуже варіюються — система нестабільна або метод хибний. В обох випадках не відправляйте у продакшн.
- Базуйте і зберігайте артефакти. Зберігайте файли fio, версії ядра, версії прошивки, sysctl і сирі виводи. Майбутньому вам це знадобиться під час інциденту.
- Перетворюйте результати у рішення. «p99 fsync < 5ms при 200 commits/sec» — це рішення. «1M IOPS» — постер.
Чеклист огляду бенчмарка (користуйтесь, щоб спіймати брехню в чужому звіті)
- Чи звіт включає розмір блоку, суміш чит/запис, iodepth, numjobs, тривалість і розмір набору даних?
- Чи включені p95/p99/p99.9 латентності, а не лише середнє?
- Чи був набір даних більшим за RAM і кеш контролера?
- Чи використовувався direct IO правильно для цільового навантаження?
- Чи був пристрій кондиціонований для steady-state записів?
- Чи була файлова система заповнена/достатньо фрагментована, щоб відобразити продакшн, або це був свіжий порожній том?
- Чи був конкурентний трафік, чи бенчмарк запускали в ізоляції?
- Чи є логи ядра з помилками/повторами під час прогона?
- Чи узгоджуються результати з таймінгами на рівні додатку?
Чого уникати (сильні думки, здобуті важким шляхом)
- Не приймайте одиночні числові бенчмарки. Жодне одне число IOPS не переживе зустрічі з реальними навантаженнями.
- Не налаштовуйте тільки на основі синтетичного тесту. Налаштування змінює поведінку під конкуренцією; якщо ви не тестували конкуренцію — ви не оцінили ризик.
- Не бенчмаркуйте на системі з невідомими фоновими задачами. Скани, відновлення, резервні копії і індексація створять «таємну варіативність». Це не таємниця.
- Не ігноруйте хвостову латентність. Вона буквально те, що відчувають користувачі і що розподілені системи підсилюють.
Поширені запитання
1) Чи марні синтетичні бенчмарки?
Ні. Вони відмінні для контрольованих порівнянь і для ізоляції змінних. Вони марні, коли їх трактують як обіцянку поведінки в продакшні без вирівнювання навантаження, стеку і конкуренції.
2) Яка найбільша причина, чому результати бенчмарка не збігаються з продакшном?
Невідповідність кешування і конкуренції. Бенчмарк часто запускають з набором даних, що поміщається в кеш, і з глибиною черги, яку додаток не може підтримувати.
Результат — завищена пропускна здатність і прихована хвостова латентність.
3) Чи завжди слід використовувати direct IO у fio?
Якщо ваше цільове навантаження використовує direct IO (багато баз даних роблять так для файлів даних), то так. Якщо ваше навантаження залежить від page cache (багато веб-сервісів), то тестуйте й буферизоване IO.
Чесна відповідь: тестуйте шлях, який ви реально запускаєте.
4) Чому вища iodepth підвищує IOPS, але іноді шкодить латентності?
Глибина черги збільшує паралелізм і можливості реупорядкування, що підвищує пропуск. Але вона також збільшує чергування, особливо при насиченні.
Більше всього страждає хвостова латентність.
5) Постачальник дав мені числа бенчмарка. Як швидко їх перевірити?
Перезапустіть мінімальний набір: один 4k тест читання з реальною iodepth/numjobs, один 4k синхронний запис/фокус на fsync і один тест послідовної пропускної здатності.
Переконайтеся, що розмір набору даних перевищує кеш, і звітуйте перцентилі.
6) Що означає «steady state» для SSD-бенчмаркінгу?
Це продуктивність після того, як пристрій був достатньо записаний, щоб garbage collection і wear leveling були активні.
Короткі тести на чистому пристрої часто вимірюють сплески кешу, а не довготривалу продуктивність.
7) Як чесно бенчмаркувати розподілену систему зберігання (мережеве сховище)?
Включіть мережу і стек клієнта. Вимірюйте перевідправлення, CPU і хвостову латентність.
Запускайте тести з кількох клієнтів одночасно, бо розподілені системи часто поводяться інакше під фан-ін навантаженням, ніж під одним клієнтом.
8) Чому мої результати fio різняться між прогонами?
Поширені причини: кешування, фонові задачі, термічний тротлінг, поведінка GC пристрою і стан файлової системи (фрагментація, вільне місце).
Якщо варіативність висока — сприймайте це як сигнал: ваше середовище неконтрольоване або сховище нестабільне.
9) Які метрики я маю вказати у звіті бенчмарка, щоб його не можна було зловживати?
Включіть: визначення навантаження (rw mix, bs, iodepth, numjobs, direct/buffered), розмір набору даних, тривалість, пропускну здатність/IOPS, перцентилі латентності і контекст системи (ядро, файлова система, опції монтування).
Якщо щось з цього відсутнє — хтось «дбайливо» неправильно інтерпретує результат.
Висновок: наступні кроки, що витримують продакшн
Синтетичні бенчмарки не брешуть через злобу. Вони брешуть через вузькість, а люди — через оптимізм.
Продакшн-системи не оптимістичні. Вони зайняті, конкурентні, брудні і повні фонового навантаження, про яке ви забули.
Наступні кроки, що дійсно допомагають:
- Виберіть 3–5 профілі бенчмарків, що відображають ваше реальне навантаження (включаючи синхронні записи, якщо вам важлива довговічність).
- Вимагайте перцентилі латентності і розмір набору даних у кожному звіті продуктивності.
- Знімайте базову лінію перед змінами і зберігайте артефакти, щоб регресії можна було приписати конкретним змінам.
- Тестуйте змішані навантаження, а не лише «fio один на порожньому томі».
- Коли сумніваєтесь — довіряйте таймінгам додатку більше, ніж панелям приладів сховища.
Мета не в тому, щоб заборонити синтетичні бенчмарки. Мета — припинити дозволяти їм ухвалювати рішення, які вони не вимірювали.
Бенчмарки — це інструменти. Продакшн — це іспит. Ведіть себе відповідно.