MySQL проти MariaDB на NVMe та SATA SSD: чому ваша БД досі повільна (і як це довести)

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

Ви купили NVMe. Перемістили директорію даних. Написали в командному каналі: «ми тепер сучасні».
І додаток усе одно таймаутиться о 9:05 ранку, ніби працює на вінчестері з 2007 року.

Ось неприємна правда: апгрейд сховища не виправить проблеми продуктивності бази даних, якщо ви не розумієте, який саме I/O виконується.
«NVMe швидкий» — це не діагноз. Це платіжне доручення.

Що насправді повільне: затримка, fsync, CPU, блокування чи запит

Коли хтось каже «база даних повільна», зазвичай мають на увазі «користувач чекає».
Ця пауза може бути спричинена диском, звісно. Але так само часто це:

  • CPU (поганий план, відсутній індекс або просто надто багато одночасних запитів)
  • Блокування/транзакції (блокування рядків, gap-блоки, metadata-lock або довгі транзакції)
  • Затримка шляху коміту (fsync, скидання redo логу, поведінка doublewrite)
  • Підсилення читання (рандомні читання, бо робочий набір не вміщується в пам’ять)
  • Підсилення запису (малі записи запускають величезну фонову роботу)
  • Мережеві й DNS-нервувальні речі (так, це досі трапляється)

NVMe може дати шалені пропускні здатності. Але бази даних купують не пропускну здатність, а передбачувану затримку.
Один спайк fsync на 99.9-му процентилі може зіпсувати ваші графіки p95 для всього ранку.

Моє операційне правило: якщо ви не виміряли, куди йде час, ви не діагностуєте — ви оповідаєте.

Цитата, яку варто тримати в голові під час вимірювань: «Надія — це не стратегія.» — генерал Гордон Р. Салліван.

MySQL vs MariaDB: де поведінка розходиться в реальному світі

Вони родичі, але не близнюки

Для більшості команд застосунків MySQL і MariaDB «відчуваються» однаково, поки вам не зателефонують о 02:00 і не потрібно розбирати
дамп ниток, затримку реплікації або регрес продуктивності після оновлення патчу.
На рівні сховища обидві сильно залежать від однієї фізики: кеші сторінок, writeback, поведінка fsync і форма вашого навантаження.
Але їхні дефолтні налаштування, фічі та поведінка на межах можуть відрізнятися настільки, щоб змінити вузьке місце.

Поведінка шляху коміту та скидання: нудні речі, що роблять вас повільними

Шлях коміту — це те, де NVMe отримує найбільшу увагу: записи в журнал і їх скидання.
Підступ у тому, що поведінка скидання в системі — це тристоронній контракт між:
налаштуваннями InnoDB, вашим файловим системою + опціями монтування і прошивкою/контролером диска.

  • innodb_flush_log_at_trx_commit вирішує, коли redo скидається при коміті (надійність проти затримки).
  • sync_binlog впливає, як часто binlog fsync’иться (безпека реплікації проти затримки запису).
  • innodb_flush_method (часто O_DIRECT) впливає на подвійне кешування і шаблон записів.
  • розмір redo логу та тиск чекпоінтів можуть перетворити пристрій із нормального на джерело джиттера.

Відмінності в інструментуванні продуктивності, які ви помітите

Сучасний MySQL має сильну історію Performance Schema і велику екосистему навколо нього. MariaDB також має хороше інструментування,
але ви знайдете відмінності в назвах таблиць, лічильниках і в тому, які очікування і як саме експонуються.
Не обирайте базу лише тому, що блог сказав, ніби вона «швидша». Обирайте за:
операційною ясністю, поведінкою реплікації, з якою ви можете жити та здатністю вашої команди дебажити під тиском.

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

NVMe vs SATA SSD: частини, що важливі для баз даних

NVMe — це не просто «швидший SSD»

Продуктивність SATA SSD формувалася інтерфейсом AHCI: обмежена глибина черги, більші накладні витрати та дизайн, який мав сенс, коли
сховище імітувало обертовий диск. NVMe — це інша модель: багато паралельних черг, низькі накладні витрати і значно вищий
потенціал IOPS.

Якщо ваше навантаження однопоточне, або домінує затримка fsync, або заблоковане через блокування рядків,
NVMe не буде відчуватися як магія. Це буде як модернізувати двигун машини, буксуючи причіп з ручним гальмом.

Бази даних турбуються про неприємні деталі

  • Розподіл затримок (p99 важливіший за «до 3.5GB/s»)
  • Поведінка кешу записів (леткий кеш + захист від втрати живлення змінює все)
  • Термічне троттлінг (NVMe приводить це тихо, як ввічливий саботажник)
  • Глибина черги і паралелізм (одна зайнята нитка не наситить NVMe)
  • Стійка продуктивність (після вичерпання SLC-кешу)

Жарт №1: Купувати NVMe, щоб полагодити повільний запит, усе одно що купити швидший ліфт, бо забули, де припаркувалися.
Поїздка стане плавнішою, але ви все ще загублені.

Коли SATA може бути «гідним» варіантом

Якщо ваш набір даних вміщується в пам’ять, читання в основному обслуговуються з buffer pool та кешів ОС. Сховище має значення насамперед для:
redo log записів, binary log записів і випадкових скидань сторінок.
Достойний SATA SSD може з цим справлятися — допоки не підніметься конкуренція і не з’являться fsync-шторм.

NVMe зазвичай блищить, коли у вас є висока конкуренція при випадковому I/O, великий робочий набір
і велике навантаження на запис — або коли вам потрібна низька затримка під навантаженням, а не лише висока пікова пропускна здатність на маркетинговому слайді.

Цікаві факти та контекст (те, що люди забувають)

  1. MariaDB з’явилася у 2009 як форк після того, як Oracle придбала Sun Microsystems, власника MySQL.
  2. InnoDB став дефолтним двигуном збереження для MySQL роки тому; раніше часто використовували MyISAM з дуже іншою I/O-поведінкою.
  3. NVMe 1.0 вийшов у 2011, і міф «NVMe робить усе швидким» з’явився незабаром після, часто без тестів, чутливих до глибини черги.
  4. Семантика fsync різниться залежно від файлової системи й опцій монтування; два сервери з ідентичними SSD можуть показувати дуже різну затримку комітів.
  5. Підсилення запису реальне: одна логічна зміна сторінки може розгорнутися в redo лог, doublewrite, скидання і фонові злиття.
  6. Числа IOPS умовні: виробники цитують їх при конкретних глибинах черги й патернах доступу, що рідко відповідають OLTP.
  7. Планувальники I/O в Linux змінювалися з часом; NVMe часто використовує інший дефолтний планувальник, ніж SATA, що впливає на затримку під навантаженням.
  8. Захист від втрати живлення важливий: «enterprise» SSD часто мають конденсатори; споживчі SSD — часто ні. Це змінює безпечне кешування записів і надійність.
  9. Реплікація залежить від fsync binlog: послаблення надійності може призвести до того, що репліки відставатимуть по-іншому, і це заплутує.

Як довести вузьке місце: 12+ практичних завдань з командами

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

Завдання 1: Підтвердіть, яке сховище ви справді використовуєте (NVMe vs SATA) і як воно підключене

cr0x@server:~$ lsblk -d -o NAME,MODEL,TRAN,ROTA,SIZE
NAME  MODEL                 TRAN ROTA  SIZE
nvme0n1 Samsung SSD 990 PRO  nvme    0  1.8T
sda   Samsung SSD 860 EVO    sata    0  1.8T

Що це означає: TRAN показує інтерфейс. ROTA=0 означає «не ротаційний» (SSD).
Рішення: якщо ваш datadir все ще на sda, ваш придбаний NVMe наразі декоративний.

Завдання 2: Перевірте datadir MySQL/MariaDB і на якій файловій системі він знаходиться

cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'datadir';"
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| datadir       | /var/lib/mysql/ |
+---------------+-----------------+

cr0x@server:~$ df -Th /var/lib/mysql
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme0n1p2 ext4  1.8T  620G  1.1T  37% /var/lib/mysql

Що це означає: ви на ext4, підкріпленому NVMe розділом nvme0n1p2.
Рішення: зафіксуйте тип файлової системи; він впливає на семантику надійності та опції тонкого налаштування.

Завдання 3: Перевірте опції монтування, що впливають на write barriers і затримку

cr0x@server:~$ findmnt -no TARGET,SOURCE,FSTYPE,OPTIONS /var/lib/mysql
/var/lib/mysql /dev/nvme0n1p2 ext4 rw,relatime,errors=remount-ro

Що це означає: базовий ext4-монтаж. Ніяких екзотичних опцій не показано.
Рішення: якщо ви бачите дивності як data=writeback або вимкнені барʼєри, розглядайте це як ревʼю ризиків, а не «перевірку продуктивності».

Завдання 4: Підтвердіть метод скидання InnoDB і вузли надійності комітів

cr0x@server:~$ mysql -e "SHOW VARIABLES WHERE Variable_name IN ('innodb_flush_method','innodb_flush_log_at_trx_commit','sync_binlog');"
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1     |
| innodb_flush_method            | O_DIRECT |
| sync_binlog                    | 1     |
+--------------------------------+-------+

Що це означає: повна надійність: скидання redo на кожен коміт; fsync binlog на кожну транзакцію.
Рішення: якщо затримка — ваша проблема і ви можете терпіти певний ризик, можна розглянути послаблення одного з параметрів — але лише після вимірювання fsync-очікувань (Завдання 10).

Завдання 5: Виміряйте здоровʼя пристрою і чи тротлінгує він або має помилки

cr0x@server:~$ sudo smartctl -a /dev/nvme0n1 | sed -n '1,25p'
smartctl 7.4 2023-08-01 r5530 [x86_64-linux-6.8.0] (local build)
=== START OF INFORMATION SECTION ===
Model Number:                       Samsung SSD 990 PRO
Serial Number:                      S7X...
Firmware Version:                   5B2QJXD7
PCI Vendor/Subsystem ID:            0x144d
IEEE OUI Identifier:                0x002538
Total NVM Capacity:                 2,000,398,934,016 [2.00 TB]
Unallocated NVM Capacity:           0
Controller ID:                      4
Number of Namespaces:               1
Namespace 1 Size/Capacity:          2,000,398,934,016 [2.00 TB]

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

Завдання 6: Перевірте температуру NVMe і сигнали термічного троттлінгу

cr0x@server:~$ sudo smartctl -a /dev/nvme0n1 | grep -E "Temperature:|Critical Warning|Thermal"
Critical Warning:                   0x00
Temperature:                        64 Celsius

Що це означає: 64°C — це тепло, але не катастрофа для багатьох дисків; пороги троттлінгу різняться.
Рішення: якщо температури зростають під час піку і це збігається зі спайками затримки — додайте повітряний потік/радіатор або перемістіть пристрій; не сперечайтесь з термодинамікою.

Завдання 7: Подивіться на погляд ядра щодо планувальника I/O і чергування

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

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

Що це означає: активний mq-deadline.
Рішення: якщо ви ганяєтеся за хвостовою затримкою, вибір планувальника може мати значення. Але міняйте його лише з вимірюванням «до/після», а не за відчуттями.

Завдання 8: Перевірте, чи не обмежує вас CPU під час «проблем зі сховищем»

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

12:01:22 PM  CPU   %usr %nice %sys %iowait %irq %soft %steal %idle
12:01:23 PM  all   62.1  0.0   9.2    1.1   0.0   0.6    0.0  27.0

Що це означає: низький iowait, високе використання user CPU. Це кричить «запити/обчислення», а не «диск повільний».
Рішення: зверніть увагу на плани запитів, контенцію та ефективність buffer pool, перш ніж знову міняти диски.

Завдання 9: Підтвердіть тиск на диск і затримку за допомогою iostat

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

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          58.10    0.00    8.90    2.40    0.00   30.60

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         520.0  68400.0     0.0    0.0    2.10   131.5     880.0  99200.0     0.0    0.0    8.70   112.7     8.3   78.0

Що це означає: write await ~8.7ms і util 78% вказують на значний тиск; NVMe все ще може бути «завантаженим», якщо ваше навантаження синхронно-щільне.
Рішення: корелюйте з InnoDB log waits і часом fsync; якщо await сплески збігаються з затримкою комітів — настроюйте шлях логів/чекпоінтів, а не buffer pool.

Завдання 10: Визначте класи очікувань MySQL/MariaDB (особливо I/O і лог)

cr0x@server:~$ mysql -e "SELECT EVENT_NAME, COUNT_STAR, SUM_TIMER_WAIT/1000000000000 AS seconds_waited
FROM performance_schema.events_waits_summary_global_by_event_name
WHERE EVENT_NAME LIKE 'wait/io/file/%' OR EVENT_NAME LIKE 'wait/synch/%'
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;"
+------------------------------------------+------------+----------------+
| EVENT_NAME                               | COUNT_STAR | seconds_waited |
+------------------------------------------+------------+----------------+
| wait/io/file/innodb/innodb_log_file      | 1823345    | 913.42         |
| wait/io/file/innodb/innodb_data_file     | 937223     | 411.08         |
| wait/synch/mutex/innodb/log_sys_mutex    | 8234432    | 210.55         |
+------------------------------------------+------------+----------------+

Що це означає: домінують очікування по файлу журналу. Це часто відповідає затримці fsync або контенції на лог-мутах.
Рішення: зосередьтеся на розмірі redo логу, налаштуваннях скидання і конкурентності комітів; один NVMe не виправить сериалізоване вузьке місце журналу.

Завдання 11: Перевірте тиск чекпоінтів InnoDB і поведінку dirty-сторінок

cr0x@server:~$ mysql -e "SHOW ENGINE INNODB STATUS\G" | sed -n '1,120p'
...
Log sequence number          834992230144
Log flushed up to            834992229120
Last checkpoint at           834991100928
...
Modified db pages            214833
Pending writes: LRU 0, flush list 12, single page 0
...

Що це означає: pending flush list і багато змінених сторінок можуть означати, що фоновий флаш відстає.
Рішення: якщо вік чекпоінта залишається високим і pending writes ростуть під час піку, розгляньте збільшення redo логу та перегляд innodb_io_capacity після вимірювання можливостей пристрою.

Завдання 12: Перевірте хітрейт buffer pool і чи читається з диска

cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';"
+---------------------------------------+------------+
| Variable_name                         | Value      |
+---------------------------------------+------------+
| Innodb_buffer_pool_read_requests      | 9823344123 |
| Innodb_buffer_pool_reads              | 92233441   |
+---------------------------------------+------------+

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

Завдання 13: Підтвердіть розмір redo логу (і чи він абсурдно малий)

cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'innodb_redo_log_capacity'; SHOW VARIABLES LIKE 'innodb_log_file_size';"
+-------------------------+------------+
| Variable_name           | Value      |
+-------------------------+------------+
| innodb_redo_log_capacity| 2147483648 |
+-------------------------+------------+
+-------------------+-----------+
| Variable_name     | Value     |
+-------------------+-----------+
| innodb_log_file_size | 0      |
+-------------------+-----------+

Що це означає: використовується ємнісне масштабування redo (2GiB тут). Маленькі логи змушують часті чекпоінти; великі логи можуть приховувати проблеми, але збільшують час відновлення після краху.
Рішення: якщо логові очікування домінують і тиск чекпоінтів високий — збільшення ємності redo часто дає чистий виграш, але спочатку перевірте цілі відновлення.

Завдання 14: Перевірте, чи вас не обмежує вільне місце файлової системи або фрагментація

cr0x@server:~$ df -h /var/lib/mysql
Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme0n1p2  1.8T  1.6T  140G  92% /var/lib/mysql

Що це означає: 92% заповнення — це запах проблем продуктивності. SSD і файлові системи поводяться гірше при майже повному заповненні; MySQL також може мати проблеми з purge та тимчасовим простором.
Рішення: вільне місце — це продуктивність. Бюджетуйте його, як CPU.

Завдання 15: Перевірте, чи тимчасові таблиці не переливаються на диск (часто помилково діагностується як «диск повільний»)

cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Created_tmp%';"
+-------------------------+---------+
| Variable_name           | Value   |
+-------------------------+---------+
| Created_tmp_disk_tables | 184223  |
| Created_tmp_tables      | 231002  |
+-------------------------+---------+

Що це означає: багато тимчасових таблиць йде на диск. Це може покарати і SATA, і NVMe, особливо якщо tmpdir знаходиться на повільнішому сховищі.
Рішення: ідентифікуйте запити, що створюють тимчасові таблиці; налаштуйте індекси або форму запиту спочатку, потім обережно налаштовуйте розміри тимчасових таблиць.

Завдання 16: Слідкуйте за реплікацією на предмет затримки, спричиненої I/O (комітні затримки можуть резонувати)

cr0x@server:~$ mysql -e "SHOW SLAVE STATUS\G" | egrep "Seconds_Behind_Master|Slave_SQL_Running|Slave_IO_Running|Relay_Log_Space"
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 87
Relay_Log_Space: 2143027200

Що це означає: відставання і великі relay логи можуть бути спричинені повільним apply через fsync-тиск, недостатній паралелізм або важкі читаючі операції.
Рішення: якщо відставання зростає під час хвиль записів — розглядайте налаштування збереження і шляху записів як частину продуктивності реплікації, а не окрему проблему.

Швидкий план діагностики

Це версія «в мене 15 хвилин і менеджер позаду». Не сперечайтесь про архітектуру. Знайдіть вузьке місце.

По-перше: підтвердьте, чи база чекає на I/O або на щось інше

  • Запустіть mpstat: якщо iowait низький, а CPU високий — це не «диск» (Завдання 8).
  • Запустіть iostat -x: подивіться await і %util для пристрою datadir (Завдання 9).
  • Перевірте топ очікувань у Performance Schema: якщо домінують очікування по файлам журналу, ви в проблемах шляху коміту (Завдання 10).

По-друге: визначте, чи це тиск на читання, запис або затримка коміту

  • Тиск на читання: зростання buffer pool reads (Завдання 12), багато дискових читань в iostat, повільні запити з повними сканами.
  • Тиск на запис: змінені сторінки + pending flushes + затримка чекпоінтів в InnoDB status (Завдання 11).
  • Затримка коміту: очікування на файли журналу і mutex-очікування плюс видимі спайки затримки на write endpoint (Завдання 10 + Завдання 4).

По-третє: перевірте шлях сховища і виключіть припущення «NVMe — значить все добре»

  • Підтвердіть, що datadir дійсно на NVMe (Завдання 1–2).
  • Перевірте здоровʼя пристрою/температуру (Завдання 5–6).
  • Підтвердіть, що опції файлової системи/монтування не роблять щось дивне (Завдання 3).

По-четверте: вирішіть, що міняти (а що не чіпати)

  • Якщо очікування вказують на запити/блокування: виправляйте запити, індекси, область транзакцій. Не міняйте параметри файлової системи, щоб компенсувати відсутні індекси.
  • Якщо очікування вказують на fsync redo/binlog: налаштовуйте розмір redo і політику комітів відповідно до ясних вимог надійності.
  • Якщо пристрій показує тротлінг/помилки: вирішіть проблеми з залізом, охолодженням, прошивкою або розміщенням перед тим, як чіпати налаштування БД.

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

1) «Ми перейшли на NVMe, але записи все ще стрибкоподібні»

Симптом: p95-спайки затримки переважно на write-ендпоїнтах; CPU виглядає нормально.

Корінна причина: шлях коміту сериалізовано через скидання redo логу, fsync binlog або контенцію log mutex; пропускна здатність пристрою тут не допоможе.

Виправлення: виміряйте log waits (Завдання 10), перевірте налаштування надійності (Завдання 4), збільште ємність redo (Завдання 13) і підтвердіть, що політика fsync binlog відповідає бізнес-потребам.

2) «Повільно лише під час звітів»

Симптом: OLTP сповільнюється, коли виконуються аналітичні/звіти.

Корінна причина: churn у buffer pool + довгі скани + spill у tmp table; сховище стає жертвою, не винуватцем.

Виправлення: знайдіть топ-скануючі запити, додайте потрібні індекси, виносьте звіти на репліку і стежте за Created_tmp_disk_tables (Завдання 15).

3) «iowait низький, але користувачі скаржаться»

Симптом: низький системний iowait; таймаути додатку збережені.

Корінна причина: контенція блокувань, «гарячі» рядки або насичення CPU. Апгрейд сховища не торкнеться цього.

Виправлення: дослідіть очікування (Завдання 10), перегляньте slow query log і тривалість транзакцій, зменшіть контенцію (батчування, індекси, коротші транзакції).

4) «Відставання репліки з’явилося після «оптимізації надійності»»

Симптом: репліки відстають під час піків; мастер здається швидким.

Корінна причина: послаблення fsync налаштувань змінило характеристику навантаження; репліки тепер обробляють піки інакше, або патерн I/O binlog/relay погіршився.

Виправлення: перевірте sync_binlog і політики комітів; вимірюйте зростання relay log і поведінку apply (Завдання 16).

5) «NVMe швидкий, але сервер зависає на кілька секунд»

Симптом: періодичні затримки; графіки показують різкі падіння латентності.

Корінна причина: термальне троттлінг, прошивкові причуди пристрою або шторм writeback при майже повному диску.

Виправлення: перевірте температуру й попередження (Завдання 6), тримайте вільне місце (Завдання 14) і перевірте поведінку ядра/пристрою під час затримок.

6) «Ми заміряли 3GB/s, отже в проді має бути все добре»

Симптом: синтетична пропускна здатність велика; продакшн не відповідає.

Корінна причина: неправильна метрика. OLTP — це дрібні випадкові читання/записи, затримка fsync і хвостова поведінка під конкуренцією.

Виправлення: використовуйте тести, наближені до робочого навантаження, зосередьтесь на p99 fsync і log waits, і порівнюйте під реалістичними рівнями конкуренції (Завдання 9–11).

Три корпоративні міні-історії з полі бою

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

Середня SaaS-компанія мігрувала свою основну базу з SATA SSD на NVMe під час планового вікна технічного обслуговування.
Вони зробили базові кроки правильно: скопіювали дані, оновили fstab, перевірили datadir. У change request було «очікуйте 3–5x покращення I/O».
Наступного ранку служба підтримки вибухнула: випадкові відмови оформлення замовлень, дивні спайки в latency при оформленні і кілька тривожних deadlock’ів.

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

Справжня проблема не була в пристрої. Це була одна «гаряча» таблиця з довгим патерном транзакцій, введеним тиждень тому.
NVMe зробив деякі частини швидшими, що підвищило конкуренцію, що підсилювало контенцію блокувань, що збільшувало хвостову латентність.
Зміна сховища співпала з інцидентом і тому взяла на себе провину. Людям подобаються прості історії.

Коли вони нарешті перевірили Performance Schema, найвищим очікуванням не було I/O. Це були lock waits і log mutex wait, викликані
сильною комітною контенцією. Вони виправили область транзакцій в додатку, додали індекс, що прибрав скан, і «інцидент NVMe» зник.
Висновок постмортему не був «не купуйте NVMe». Він був «не перетворюйте кореляцію на каузальність лише тому, що це зручно в Slack».

Міні-історія №2: Оптимізація, що зіграла злий жарт

Інша організація мала кластер MariaDB на хороших NVMe, але затримка коміту шкодила їхньому API.
Хтось запропонував класичний хід: послабити надійність. Вони змінили innodb_flush_log_at_trx_commit і sync_binlog
щоб рідше робити fsync. Латентність запису впала. Усі аплодували. Зміню визнали «безпечним», бо «в нас є репліки».

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

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

Вони відкотили налаштування, а потім виправили справжній вузький шлях: контенцію логу і тиск чекпоінтів.
Вони змінили розмір redo логу, перевірили охолодження, щоб уникнути троттлінгу, і відокремили binlog на інший том.
Латентність API знову поліпшилася — без брехні користувачам про надійність.

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

Команда фінансових сервісів працювала на MySQL на NVMe, але вони ставилися до сховища як до компонента надійності, а не як до етикетки продуктивності.
У них була рутина: щотижневі перевірки SMART, базові температурні профілі під піком і невеликий набір «золотих команд», зафіксованих у ранбуках.
Вони також відстежували p99 fsync як метрику першого порядку.

Одного вівторка вони помітили тонке підвищення латентності запису — нічого драматичного, але достатньо, щоб зрушити API p95 вгору.
Зʼявилися типові теорії «це мережа». Інженер не сперечався; відкрив ранбук і запустив перевірки.
SMART показав температуру, що росте, iostat — зростання w_await під навантаженням.

Вони знайшли вентилятор у шасі, що вийшов з ладу. NVMe почав троттлити під піком.
Замінити вентилятор, відновити повітряний потік — латентність повернулася до базової. Ніяких аварій, ніяких великих змін або «академічних» звітів.
Виправлення було нудне. Результат — прекрасний.

Жарт №2: Найкраща оптимізація продуктивності іноді — це вентилятор за $20 — бо електронам теж не подобається, коли їх обсмажують.

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

Крок за кроком: ізолювати «сховище повільне» від «база даних повільна»

  1. Підтвердіть розміщення: підтвердіть, що datadir і tmpdir на очікуваному пристрої (Завдання 1–2).
  2. Підтвердження системного тиску: mpstat + iostat під час повільного вікна (Завдання 8–9).
  3. Перевірте очікування БД: топ-очікування Performance Schema і InnoDB status (Завдання 10–11).
  4. Класифікуйте навантаження:

    • Якщо домінують log waits: шлях коміту/ fsync.
    • Якщо домінують data file reads: проблема памʼяті/планів запитів.
    • Якщо домінують mutex/lock waits: проблема контенції/дизайну транзакцій.
  5. Перевірте здоровʼя заліза: SMART-попередження і температура (Завдання 5–6).
  6. Робіть одну зміну за раз, з capture «до/після» і планом відкотування.

Чекліст: готовність NVMe для MySQL/MariaDB

  • Диск має захист від втрати живлення, якщо ви покладаєтеся на безпечне кешування для латентності.
  • Терміка моніториться; потік повітря в шасі перевірений під піком.
  • Вибір файлової системи та опції монтування стандартизовані по флоту.
  • Налаштування redo/binlog відповідають бізнес-вимогам надійності (не лише бенчмаркам).
  • Є запас ємності (не тримайтеся на 90%+ заповнення, якщо вам не подобаються сюрпризи).
  • Ви можете відповісти: «яка топ-очікування на піку?» і «p99 fsync time?»

Чекліст: рішення MySQL vs MariaDB (практичний погляд)

  • Сумісність: підтвердіть функціональну парність, на яку ви покладаєтесь (режим реплікації, GTID, інструменти).
  • Наблюваність: обирайте ту, яку ваша команда швидко зможе дебажити з наявними навичками і дашбордами.
  • Дисципліна оновлень: обирайте екосистему, де ви можете регулярно патчити з прогнозованою поведінкою.
  • Операційні інструменти: бекапи, верифікація, фейловер, міграції схем — це важливіше за мікробенчмарки.

Питання й відповіді (FAQ)

1) Чи NVMe завжди перевершить SATA SSD для MySQL?

Не завжди в способах, які ви відчуєте. Якщо ви обмежені CPU, блокуваннями або ваш робочий набір вміщується в памʼять, NVMe нічого не змінить.
NVMe проявляє себе при високій конкуренції випадкового I/O і коли потрібна нижча хвостова затримка під постійним навантаженням.

2) Чому «%iowait» залишається низьким, навіть коли запити повільні?

Тому що процес може чекати на блокування, планувальник CPU, затори памʼяті або внутрішні mutex-очікування MySQL.
Також iowait — це метрика обліку CPU, а не прямий вимір дискової затримки. Краще використовувати iostat і DB wait events.

3) Чи безпечно ставити innodb_flush_log_at_trx_commit=2?

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

4) Мої log file waits домінують. Який перший поворот ручки?

Спочатку виміряйте. Потім розгляньте ємність redo логу (занадто мала викликає часті чекпоінти) і частоту fsync binlog.
Якщо надійність має залишатися суворою (1/1), швидше за все вам знадобляться кращі низькозатримні пристрої, SSD з PLP або зменшення конкурентності комітів на стороні додатку.

5) Чи має значення вибір файлової системи (ext4 vs XFS) для продуктивності бази даних?

Може, головним чином через поведінку латентності при writeback і те, як обробляються метадані й алокація.
Більший виграш — це узгодженість і вимірюваність по хостам. Оберіть одну, стандартизуйте опції монтування і базуйтеся на p99 fsync latency.

6) Який найпростіший спосіб зрозуміти, чи я read-bound чи write-bound?

Дивіться Innodb_buffer_pool_reads і iostat читання проти записів, потім перехресно перевіряйте Performance Schema.
Високі дискові читання і очікування по data file вказують на тиск читання. Високі log waits і pending flushes — на тиск запису/коміту.

7) Як «швидший диск» може погіршити контенцію блокувань?

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

8) Чи придатні споживчі NVMe диски для продакшену баз даних?

Іноді—для не критичних навантажень. Для систем, чутливих до надійності, відсутність захисту від втрати живлення і непередбачувана стійка латентність
часто є неприйнятними. Навіть коли вони «швидкі», їхні режими відмови рідко ввічливі.

9) MySQL vs MariaDB: хто швидший на NVMe?

Залежить від версії, навантаження, конфігурації і використаних фіч. У реальних операціях «швидший» менш важливий за
«передбачувано дебажуваний» і «поводиться добре під відмовами». Бенчмаркуйте своє навантаження і порівнюйте профілі очікувань, а не тільки QPS.

10) На яку єдину метрику варто ставити алерт, щоб рано помітити проблеми зі сховищем у БД?

Якщо можна вибрати одну, ставте алерт на латентність, пов’язану з комітами, або на log file wait time (з інструментування БД) плюс температуру пристрою.
Ці дві метрики ловлять дивовижну кількість реальних проблем.

Висновок: практичні наступні кроки

NVMe — чудовий інструмент. Але він не замінює розуміння профілю очікувань вашої бази даних.
Якщо ваш MySQL або MariaDB все ще здається повільним після переходу з SATA SSD на NVMe, нічого не припускайте і вимірюйте все, що має значення:
шлях коміту, тиск чекпоінтів, пропуски buffer pool і стан пристрою.

  1. Запустіть швидкий план діагностики під час повільного вікна і збережіть виводи.
  2. Класифікуйте вузьке місце (читання vs запис/коміт vs контенція/CPU).
  3. Виправте найбільш ефективне обмеження першим: плани/блокування, розмір redo/чекпоінти або терміка/здоровʼя обладнання.
  4. Робіть одну зміну за раз. Майте план відкату. Базуйтеся на p95/p99 латентності, а не лише на пропускній здатності.

Ваша мета не «NVMe скрізь». Ваша мета — база даних, що поводиться передбачувано на піку, чесно падає і яку втомлені люди можуть швидко дебажити.

← Попередня
Debian 13: розділений DNS для VPN і LAN — надійне налаштування, яке не ламається після перезавантаження
Наступна →
Електронна пошта: include у SPF — як спростити, не порушивши доставку

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