MariaDB vs MongoDB: Спалахи записів — хто переживе піки без краху

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

Ваша система спокійна. Графіки нудні. А потім маркетинг «запускає» щось, партнер починає агресивно повторювати запити або один cron вирішує перевінчити індекс всесвіту. Письмовий трафік підіймається вертикально. Затримка слідує. Раптом ви дізнаєтеся, що насправді робить ваша база даних, коли їй страшно.

Це не релігійна війна між SQL і NoSQL. Це посібник виживання під час спалахів записів: що роблять MariaDB (InnoDB) і MongoDB (WiredTiger) під тиском, де вони відмовляють, як швидко діагностувати вузьке місце і які зміни реально знижують ризик в production.

Що таке спалах записів насправді (і чому це боляче)

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

Під стабільним навантаженням MariaDB і MongoDB можуть виглядати героїчно. Під час сплесків ілюзія закінчується, бо обидва рушії врешті-решт стикаються зі стіною, і вони мають або:

  • застосувати зворотний тиск (клієнти чекають; черги ростуть; хвостова затримка вибухає),
  • відмовитися від стійкості (підтвердження до того, як дані безпечно збережені),
  • або звалитися (OOM, диск заповнений, спіраль відставання реплік, виснаження потоків).

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

Цікаві факти та історичний контекст

  • MariaDB з’явилась після того, як Oracle придбав Sun (а отже і MySQL), і була спрямована більше питаннями управління та ліцензування, ніж лише продуктивністю.
  • MongoDB популяризувала зручну для розробника модель документів у часи, коли шардинг реляційних баз ще був переважно «вікенд-проєктом і майбутнім жалем».
  • InnoDB (рушій за замовчуванням у MariaDB) центрує стійкість навколо редо-логу та фонового скидання — записи це не просто записи, це лог-записи плюс пізніші скидання сторінок.
  • WiredTiger MongoDB використовує журнал попереднього запису (write-ahead log) і чекпоінти; поведінка під час спалахів часто залежить від ритму чекпоінтів і тиску кешу.
  • Group commit значно покращив транзакційні бази при спалахах, об’єднуючи витрати на fsync між кількома транзакціями.
  • Write concern MongoDB (w:1, majority, journaling) фактично є перемикачем між «швидко» і «доказово стійко», і ваш вибір важить значно більше під час сплесків.
  • Відставання реплікації — це не просто «проблема репліки»; воно може повертати вплив на первинний вузол, коли клієнти вимагають majority-підтверджень.
  • Впровадження NVMe змінило форму вузьких місць: з високопродуктивними пристроями CPU, контенція та серіалізація логів можуть стати обмежувачем раніше.
  • Хмарні мережі зробили «час підтвердження запису» проблемою розподілених систем: majority-записи можуть бути обмежені затримкою найповільнішого голосу, а не CPU первинного вузла.

MariaDB під час спалахів: реальність InnoDB

The write path that matters

У InnoDB типовий транзакційний запис включає:

  1. Зміни сторінок у buffer pool (пам’ять) і позначення їх як dirty.
  2. Додавання редо-записів до буфера редо-логу.
  3. На коміті забезпечення стійкості редо відповідно до innodb_flush_log_at_trx_commit.
  4. Пізніше, фонове скидання dirty-сторінок у файли даних.

Під час спалахів три речі домінують:

  • Латентність стійкості редо-логу (витрати на fsync і серіалізація логу).
  • Накопичення dirty-сторінок (заповнення buffer pool, а потім примусове скидання).
  • Контенція (рядові блокування, обслуговування вторинних індексів, «гарячі» сторінки, а іноді й метадані блокування).

Як MariaDB «переживає» спалах

MariaDB, як правило, переживає сплеск, якщо:

  • Ваше сховище має передбачувану латентність fsync (а не просто високі IOPS).
  • Ваш редо-лог налаштований під розміри та конфігурацію, які уникнуть постійного «тиску на скидання».
  • Ви уникаєте патологічних вторинних індексів на таблицях із великим навантаженням записів.
  • Ви визнаєте, що сувора стійкість коштує, і налаштовуєтеся відповідно, а не вдаєтесь, що це безкоштовно.

Режим відмови MariaDB під час спалахів зазвичай — вибух затримок, а не миттєвий крах — якщо тільки ви не загнали її в swap, не заповнили диск або не дозволили спіралі відставання реплікації/обробки з’єднань.

Ручки InnoDB, які справді мають значення під час піків

  • innodb_flush_log_at_trx_commit: 1 — найбезпечніше; 2 — часто краще для пропускної здатності; 0 — «надіюся, що живлення ніколи не зникне».
  • sync_binlog: якщо ви використовуєте binlog (реплікація), це інша половина стійкості. Встановлення в 1 — безпечно і може бути дорогим.
  • innodb_log_file_size і innodb_log_files_in_group: більші логи вирівнюють сплески; занадто малі змушують агресивно скидати.
  • innodb_io_capacity і innodb_io_capacity_max: якщо занизькі, dirty-сторінки накопичуються; надто високі — можна позбавити фонового I/O.
  • innodb_buffer_pool_size: достатньо пам’яті запобігає боротьбі читань із записами; занадто багато може приховати проблеми, поки чекпоінт не вдарить як вантажівка.
  • innodb_flush_method=O_DIRECT: часто зменшує подвійне кешування на Linux.

Зворотний тиск у MariaDB: головним чином неявний

MariaDB не дає простого регулятора «глибина черги». Зворотний тиск проявляється як:

  • Зростання латентності комітів (fsync редо).
  • Потоки, що чекають на блокування або I/O.
  • Відставання реплікації (якщо записи також породжують binlog і репліки не встигають за потоком).

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

MongoDB під час спалахів: реальність WiredTiger

The write path that matters

Поведінка записів у MongoDB сильно залежить від write concern і журналювання, але звичайний шлях такий:

  1. Запис надходить на primary і оновлює структури в пам’яті (WiredTiger cache).
  2. Додається журнал (write-ahead log); стійкість залежить від журналювання і інтервалів коміту.
  3. Реплікація відправляє операції другорядним вузлам через oplog; write concern majority чекає голосів від виборців.
  4. Чекпоінти періодично скидають дані на диск, викликаючи сплески I/O.

Як MongoDB «переживає» спалах

MongoDB виживає під час спалахів, коли:

  • Ваш диск може поглинути журналювання + I/O чекпоінтів без довгих хвостових fsync-стрибків.
  • Ви не працюєте так гаряче, що WiredTiger cache постійно висуває dirty-сторінки.
  • Топологія реплікації може витримувати majority-підтвердження (або ви готові ослабити write concern під час сплесків).
  • Ваші документи й індекси спроєктовані для локальності записів (або принаймні не саботують її).

Найнеприємніший режим відмови MongoDB — це відставання реплікації + majority write concern + повільний диск. Ця комбінація перетворює спалах на самонанасний розподілений синхрон.

Ручки WiredTiger і поведінки, що проявляються під час піків

  • Write concern: w:1 проти majority, і j:true. Це ваш пульт між затримкою і стійкістю.
  • Чекпоінтинг: чекпоінти створюють періодичні стрибки I/O; якщо система вже напружена, чекпоінти можуть посилити поведінку затримок.
  • Тиск кешу: коли кеш заповнений, евікція стає прихованим регулятором пропускної здатності записів.
  • Розмір oplog: занадто малий — другорядні вузли відстають; занадто великий — змінюються часи відновлення, сховище й профіль I/O.
  • Письмова ампліфікація індексів: кожен вторинний індекс — це додаткові операції. MongoDB не звільнений від фізики.

Зворотний тиск у MongoDB: більш явний, але легше неправильно витлумачити

MongoDB може застосовувати зворотний тиск, коли не встигає журналювати/виконувати чекпоінти або коли реплікація не може задовольнити write concern достатньо швидко. На практиці ви помітите:

  • Черги в драйвері, а потім таймаути.
  • Збільшення активності «WT cache eviction».
  • Зростання відставання oplog, поки не почнуться вибори, відкадрування або проблема зі старістю читань.

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

Хто «переживає» піки: таблиця рішень, яку можна захищати

If you need strict transactional guarantees under bursts

Віддавайте перевагу MariaDB, коли потрібна багаторядкова транзакційна цілісність, складні обмеження і передбачувана семантика під час спалахів. Поведінка InnoDB добре вивчена: вартість коміту пов’язана зі стійкістю логу і контенцією, а не з таємницею.

MongoDB теж може бути стійкою і консистентною, так. Але як тільки ви вимагаєте majority і журналювання, ви потрапляєте в землю розподіленої латентності. Під час сплесків ця земля швидко дорожчає.

If you need flexible schema and you can tolerate tuning write concern

Віддавайте перевагу MongoDB, коли модель документів — це справжня модель ваших даних (а не «нам не хотілося проектувати таблиці»), і ви можете явно вибирати рівні стійкості під час сплесків.

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

If your spikes are “bursty ingestion” and reads are secondary

Обидві системи можуть приймати записи. Різниця в тому, де вони платять:

  • MariaDB платить під час коміту (fsync редо/binlog), а потім через скидання, якщо ви перевищите ліміти dirty-сторінок.
  • MongoDB платить через журналювання і чекпоінти, а потенційно ще й через відставання реплікації, коли write concern суворий.

If you can only afford one reliable thing: predictable latency

Тут я суб’єктивний: обирайте систему, режим відмов якої ви зможете оперувати.

  • MariaDB зазвичай деградує в «повільно але правильно» при сенсовій конфігурації.
  • MongoDB може деградувати в «швидко, але не там, де ви вважаєте правду», якщо ви ставилися легковажно до write concern, здоров’я реплікації або диску.

Жарт №1: Спалах записів — це просто ваші користувачі, які запускають тест навантаження, на який ви не заклалися.

The quote you should tape to the dashboard

Надія — не стратегія. — General Gordon R. Sullivan

Ця фраза витримала випробування часом, бо це істина про production-записи.

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

У вас є 10 хвилин, перш ніж хтось запропонує «просто додати більше подів». Ось що перевірити першим, другим, третім — щоб ідентифікувати справжнє вузьке місце, а не лікувати симптоми.

First: is it disk flush latency, or CPU/locks?

  • Перевірте завантаження диска та await: якщо await високий і util на максимумі, ви обмежені I/O.
  • Перевірте CPU steal і насичення: якщо CPU завантажений або вас тротлить, ви обмежені обчисленнями.
  • Перевірте очікування блокувань: якщо потоки чекають блокувань, I/O графіки можуть вводити в оману.

Second: is durability configuration forcing syncs on every write?

  • MariaDB: innodb_flush_log_at_trx_commit, sync_binlog, формат binlog, пакетування комітів.
  • MongoDB: write concern (w, j), інтервали комітів, очікування majority.

Third: is replication the hidden limiter?

  • MariaDB: репліки застосовують binlog повільно, налаштування semi-sync або повільне сховище на репліках.
  • MongoDB: другорядні вузли відстають, вибори, majority write concern чекає на хворий вузол.

Fourth: are you checkpointing/flushing too aggressively (or too late)?

  • MariaDB: відсоток dirty-сторінок, тиск редо-логу, налаштування фонового скидання.
  • MongoDB: швидкість евікції WiredTiger, тривалості чекпоінтів, тиск журналу.

Fifth: are indexes and schema the real tax?

Сплески виявляють ампліфікацію записів. Схема, яка «добре працювала» при 1k записів/с, може розвалитися при 20k записів/с, бо кожен запис зачіпає надто багато індексів, гарячих ключів або вторинних структур.

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

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

1) Linux: confirm disk saturation and latency

cr0x@server:~$ iostat -x 1 5
Linux 6.5.0 (db01)  12/30/2025  _x86_64_  (8 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          12.10    0.00    6.20   18.40    0.00   63.30

Device            r/s     w/s   rMB/s   wMB/s  avgrq-sz  avgqu-sz   await  r_await  w_await  svctm  %util
nvme0n1         110.0  4200.0    3.2   180.5     87.1      35.2    8.4      1.9      8.6   0.23  99.2

Що це означає: %util близько до 100 і високе avgqu-sz показують глибоку чергу. Очікування запису ~8.6ms. Під час сплесків це часто стає 20–100ms, і бази починають тайм-аутитись.

Рішення: Якщо await росте з навантаженням, ви обмежені I/O. Зменшуйте частоту fsync (обережно), пакетування комітів або переходьте на швидше/менш завантажене сховище.

2) Linux: check pressure stalls (CPU/memory/IO contention)

cr0x@server:~$ cat /proc/pressure/io
some avg10=12.45 avg60=8.21 avg300=2.14 total=9382211
full avg10=4.10 avg60=2.01 avg300=0.50 total=1923112

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

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

3) Linux: verify filesystem space and inode headroom

cr0x@server:~$ df -h /var/lib/mysql /var/lib/mongodb
Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme0n1p2  1.8T  1.6T  120G  94% /
/dev/nvme1n1p1  1.8T  1.2T  560G  69% /data

Що це означає: 94% зайнято — це на межі проблем продуктивності і операційних помилок. Деякі файлові системи поводяться погано, коли майже заповнені; бази даних поводяться погано, коли не можуть розширити файли.

Рішення: Якщо під час спалаху ви вище ~90%, пріоритезуйте звільнення місця або додавання ємності перед тим, як ганятися за планами запитів.

4) MariaDB: see what the server thinks is happening right now

cr0x@server:~$ mysql -e "SHOW FULL PROCESSLIST\G" | head -n 40
*************************** 1. row ***************************
     Id: 4312
   User: app
   Host: 10.10.2.14:51132
     db: prod
Command: Query
   Time: 12
  State: Waiting for redo log flush
   Info: COMMIT
*************************** 2. row ***************************
     Id: 4321
   User: app
   Host: 10.10.2.18:51410
     db: prod
Command: Query
   Time: 8
  State: Updating
   Info: INSERT INTO events ...

Що це означає: «Waiting for redo log flush» — яскрава ознака: коміти обмежені стійкістю логу. Це класичний біль під час спалаху записів.

Рішення: Досліджуйте латентність fsync, розміри редо-логу і налаштування стійкості. Зараз не час додавати індекси; ви тонуєте в витратах на скидання.

5) MariaDB: confirm durability settings (the real ones)

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

Що це означає: Це «максимальна безпека»: fsync редо при кожному коміті, fsync binlog при кожному коміті. Під час сплесків це може перетворитися на пожежу латентності комітів, якщо ваше сховище не відмінне.

Рішення: Якщо бізнес може дозволити невелику можливість втрати при відключенні живлення, розгляньте innodb_flush_log_at_trx_commit=2 і/або sync_binlog=100 для інтенсивного інжесту — після свідомого аналізу ризиків.

6) MariaDB: inspect InnoDB dirty pages and flush pressure

cr0x@server:~$ mysql -e "SHOW ENGINE INNODB STATUS\G" | egrep -i "Modified db pages|Log sequence number|Log flushed up to|pages flushed" -n | head
121:Log sequence number          98422341122
122:Log flushed up to            98422338816
401:Modified db pages            812345
405:Pages flushed up to          255112233

Що це означає: Велика кількість modified pages вказує на накопичення dirty-сторінок. Якщо «Log flushed up to» відстає від LSN під час спалаху, коміти чергуються за fsync.

Рішення: Якщо dirty-сторінки залишаються високими і скидання не встигає, налаштуйте I/O capacity і розмір редо-логу. Якщо fsync повільний — виправляйте сховище в першу чергу.

7) MariaDB: detect lock contention hot spots

cr0x@server:~$ mysql -e "SELECT * FROM information_schema.INNODB_LOCK_WAITS\G" | head -n 60
*************************** 1. row ***************************
requesting_trx_id: 123456789
requested_lock_id: 123456789:45:3:12
blocking_trx_id: 123456700
blocking_lock_id: 123456700:45:3:12

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

Рішення: Якщо очікування блокувань корелюють зі сплесками, виправляйте патерни доступу (ключі шардінгу, партиціювання, уникайте гарячих лічильників), а не налаштовуйте fsync.

8) MariaDB: verify buffer pool hit rate and read/write contention

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

Що це означає: Якщо фізичні читання зростають під час спалаху записів, ваш buffer pool може бути замалий або ви трешите. Dirty-сторінки також важливі: їхня надлишкова кількість провокує скидання в штормовому режимі.

Рішення: Якщо читання зростають разом із записами, додайте пам’ять або зменшіть тиск читань (кеш, змініть запити). Якщо dirty-сторінок багато — налаштуйте скидання і розміри логів.

9) MongoDB: check replica set health and lag

cr0x@server:~$ mongosh --quiet --eval 'rs.status().members.map(m=>({name:m.name,state:m.stateStr,health:m.health,lagSeconds:(m.optimeDate?Math.round((new Date()-m.optimeDate)/1000):null)}))'
[
  { name: 'mongo01:27017', state: 'PRIMARY', health: 1, lagSeconds: 0 },
  { name: 'mongo02:27017', state: 'SECONDARY', health: 1, lagSeconds: 6 },
  { name: 'mongo03:27017', state: 'SECONDARY', health: 1, lagSeconds: 84 }
]

Що це означає: Один secondary відстає на 84 секунди. Якщо клієнти використовують w:"majority", це відставання може прямо додавати затримку (або таймаути) залежно від голосування і вимог write concern.

Рішення: Якщо потрібні majority-підтвердження, виправте повільний вузол (диск, CPU, мережа) або тимчасово приберіть його з голосування з контролем змін.

10) MongoDB: confirm write concern used by the application

cr0x@server:~$ mongosh --quiet --eval 'db.getMongo().getWriteConcern()'
{ w: 'majority', wtimeout: 0 }

Що це означає: Majority-записи. Добре для правильності; під час сплесків ви тепер залежите від здоров’я реплікації та міжвузлових затримок.

Рішення: Під час планованих інжест-сплесків розгляньте інший write concern лише якщо дані можна відновити і ризик задокументований. Інакше масштабуйте репліка-сет та сховище відповідно до вимог.

11) MongoDB: check WiredTiger cache pressure and eviction churn

cr0x@server:~$ mongosh --quiet --eval 'var s=db.serverStatus().wiredTiger.cache; ({ "bytes currently in cache": s["bytes currently in the cache"], "tracked dirty bytes": s["tracked dirty bytes in the cache"], "pages evicted": s["pages evicted"] })'
{
  "bytes currently in cache": 29192355840,
  "tracked dirty bytes": 9423123456,
  "pages evicted": 182341122
}

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

Рішення: Якщо евікція інтенсивна під час сплесків, перегляньте розмір кешу, розмір документів/індексів і пропускну здатність диска. Не «просто додавайте ОЗП», не перевіривши поведінку чекпоінтів.

12) MongoDB: inspect current operations for lock/IO symptoms

cr0x@server:~$ mongosh --quiet --eval 'db.currentOp({active:true,secs_running:{$gte:2}}).inprog.slice(0,3).map(o=>({opid:o.opid,secs:o.secs_running,ns:o.ns,desc:o.desc,waitingForLock:o.waitingForLock,locks:o.locks}))'
[
  {
    opid: 18231,
    secs: 9,
    ns: 'prod.events',
    desc: 'conn31291',
    waitingForLock: false,
    locks: { Global: 'w' }
  },
  {
    opid: 18247,
    secs: 5,
    ns: 'prod.events',
    desc: 'conn31340',
    waitingForLock: false,
    locks: { Global: 'w' }
  }
]

Що це означає: Довготривалі записи можуть вказувати на затримки I/O, контенцію індексів або тиск журналювання. Сучасний MongoDB має дрібнозернисті блокування, але присутність глобальних записів все ще може проявлятись в агрегатах.

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

13) Linux: confirm you’re not being throttled by cgroups

cr0x@server:~$ systemctl show mariadb -p CPUQuota -p MemoryMax
CPUQuota=50%
MemoryMax=8589934592

Що це означає: Ви віддали базі даних половину CPU і 8GB RAM і очікуєте, що вона проковтне сплески. Сміливо.

Рішення: Приберіть штучні обмеження для stateful сервісів, або явно проєктуйте їх із контролем прийняття та чергуванням.

14) Linux: check swap activity (the silent killer)

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 4  2  524288 112340  8204 3124000  40  120   210  1820  980 2200 22  7 48 23  0

Що це означає: Свайп ін/аут під час сплесків перетворює «швидке сховище» на «повільну муку». Латентності баз даних стають необмеженими.

Рішення: Зменшіть тиск пам’яті (буфери, розміри кешу), виправте сумісні навантаження або перемістіть базу на хост, який не ставиться до ОЗП як до опціонального ресурсу.

Три корпоративні міні-історії (як це ламається в реальному житті)

Mini-story #1: The incident caused by a wrong assumption

Середня SaaS-компанія використовувала MongoDB для інжесту подій. Модель даних мала сенс: події були документами, схема змінювалася щотижня, шардинг був у планах. Вони мали replica set з трьома членами в різних зонах і вважали себе досить зрілими.

Потім партнерська система почала повторювати запити при 500 без джиттера. Записи підскочили, CPU первинного залишався прийнятним. Команда припустила, що «MongoDB витримає високу пропускну здатність», бо раніше все було нормально. Проте затримка все одно зросла, і додаток почав тайм-аутитись на записах з w:"majority". Командир інциденту дивився на графіки диска первинного і бачив лише «зайнято», а не катастрофу.

Неправильне припущення було тонким: вони думали, що majority write concern означає «два з трьох, завжди швидко». Насправді один secondary був деградований тижнями — достатньо здоровий, щоб голосувати, але недостатньо здоровий, щоб не відставати. Під час сплеску він ще більше відстав. Majority-підтвердження тепер залежали від найповільнішого голосу, який іноді встигав наздогнати нові операції.

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

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

Mini-story #2: The optimization that backfired

Платформа електронної комерції використовувала MariaDB для замовлень і інвентарю. Вони очікували сплесків під час запусків, тому налаштували швидкість: більший buffer pool, агресивні налаштування потоків, і встановили innodb_flush_log_at_trx_commit=2 щоб зменшити тиск fsync. Це спрацювало. Латентність комітів впала. Усі святкували.

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

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

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

Mini-story #3: The boring but correct practice that saved the day

Фінтех-подібна компанія (та, що каже «фінтех», але в основному продає підписки) використовувала обидві: MariaDB для транзакцій і MongoDB для аудиторських подій. Вони жили в світі комплаєнсу й незручних питань, тож були алергічні до «просто встановити в 0».

Вони також робили нудне, але правильне: щомісячну «репетицію сплеску». Не синтетичний бенчмарк у лабораторії — контрольоване збільшення навантаження в staging з об’ємами даних, схожими на production, і тим самим класом сховища. Вони тренували відмови: відставання реплікації, інжекцію затримки диска, переключення primary. Хтось завжди скаржився, що це забирає час. Хтось інший завжди знаходив щось важливе.

Одного місяця репетиція виявила, що новий secondary MongoDB у іншій зоні мав гіршу латентність fsync. Majority-записи здавались нормальними при звичайному трафіку і ставали проблемою лише при подвоєнні швидкості записів. Вони виправили це до реальної кампанії, перемістивши вузол на кращий рівень сховища і відрегулювавши голосування, щоб повільний член не диктував латентність підтверджень.

Під час реального сплеску тижнями пізніше обидві бази працювали гаряче, але стабільно. Команда не виглядала блискучою. Вона виглядала нудною. Саме в цьому і сенс.

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

1) Symptom: commits stall, many threads “Waiting for redo log flush” (MariaDB)

Корінна причина: латентність fsync або серіалізація редо-логу стає обмежувачем; занадто малий лог підвищує тиск.

Виправлення: Перейдіть на нижчелатентне сховище; збільшіть розмір редо-логу; зіставте innodb_flush_log_at_trx_commit і sync_binlog з бізнес-вимогами стійкості; переконайтеся, що binlog і редо на адекватному сховищі.

2) Symptom: sudden write latency spikes every few minutes (MongoDB)

Корінна причина: цикли чекпоінтів/скидання журналу викликають періодичні I/O-сплески; погіршується тиск кешу.

Виправлення: Забезпечте пропускну здатність диска і низьку хвостову латентність; зменшіть ампліфікацію записів (індекси, розмір документів); переконайтеся, що WiredTiger cache не виганяє OS page cache; перегляньте поведінку чекпоінтів у метриках.

3) Symptom: MongoDB writes time out only when using majority

Корінна причина: один голосуючий secondary відстає або повільний; majority-підтвердження тепер включає повільний шлях.

Виправлення: відремонтуйте/замініть повільний secondary; розгляньте зміну голосуючих членів; виправте мережу і сховище; збільште oplog, якщо secondaries відпадають.

4) Symptom: MariaDB CPU is fine, but QPS collapses

Корінна причина: контенція блокувань (гарячі рядки, gap locks, довгі транзакції) або I/O wait; графіки CPU вводять в оману.

Виправлення: ідентифікуйте очікування блокувань; зменшіть обсяг транзакцій; уникайте гарячих лічильників; змініть ізоляцію або патерн доступу; додавайте індекси лише якщо вони зменшують час блокувань (а не тільки «для читань»).

5) Symptom: both databases “randomly” get slow during bursts in VMs

Корінна причина: шумні сусіди і контенція на сховищі; змінна латентність fsync; CPU steal.

Виправлення: ізолюйте сховище; виділіть диски; виміряйте хвостову латентність fsync; перевірте CPU steal; припиніть співрозміщення пакетних робіт з базою даних.

6) Symptom: write burst causes a retry storm and then everything dies

Корінна причина: клієнтські повтори без backoff; база стає регулятором швидкості; таймаути посилюють навантаження.

Виправлення: експоненційний backoff з jitter; circuit breakers; серверна admission control; обмеження конкурентності; повернення 429/503 навмисно замість того, щоб дозволяти таймаутам створювати каскадування.

7) Symptom: “We scaled up disk IOPS but it’s still slow”

Корінна причина: ви обмежені серіалізацією (mutex логу, один гарячий шард), CPU або мережевою латентністю реплікації, а не сирими IOPS.

Виправлення: виміряйте, де витрачається час (fsync, блокування, підтвердження реплікації); зменшіть гарячі місця; шардуйте/партиціюйте для розподілу записів; перевірте, що ви отримали нижчу хвостову латентність, а не тільки вищу пікову пропускну здатність.

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

Step-by-step: preparing MariaDB for predictable write bursts

  1. Виміряйте хвостову латентність fsync на реальному типі тому, що використовується для редо/binlog. Якщо p99 поганий — зупиніться і виправляйте сховище спочатку.
  2. Задайте стійкість свідомо: вирішіть innodb_flush_log_at_trx_commit і sync_binlog з документованою заявою про ризики.
  3. Правильно розмірюйте редо-логи щоб вирівняти сплески і зменшити тиск на скидання.
  4. Аудитируйте вторинні індекси на таблицях з інтенсивними записами. Приберіть «вітальні» індекси. Залишайте ті, що запобігають повним сканам, які дуже блокують.
  5. Контролюйте розмір транзакцій: невеликі коміти легше пакетувати і реплікувати; великі транзакції створюють шторм блокувань та скидання.
  6. Плануйте зворотний тиск: ставте розумні таймаути, обмежуйте конкурентність застосунку, реалізуйте jittered повтори.
  7. Реплікаційна репетиція: підтвердіть, що репліки встигають застосовувати при швидкості сплеску; інакше репліки стануть проблемою часу відновлення.

Step-by-step: preparing MongoDB for predictable write bursts

  1. Визначте write concern для кожного навантаження (не «по настрою»). Критичні записи: majority+journal. Телеком-дані, які можна відновити: можливо нижче, з охоронними заходами.
  2. Моніторте відставання реплікації і вибори як SLO першого порядку. Під час сплесків це — правда.
  3. Підтвердіть сховище для журналювання і чекпоінтів: низька хвостова латентність важливіша за загальні IOPS.
  4. Виберіть shard keys для розподілу записів, якщо шардите. Гарячі шарди перетворюють «розподілене» в «більше болю на одному вузлі з додатковими кроками».
  5. Дисципліна індексів: кожен індекс — податок на ваш бюджет записів. Залишайте тільки ті, що служать реальним запитам.
  6. Ємність для кешу + евікції: слідкуйте за dirty bytes і churn евікцій; уникайте постійної роботи «на межі».
  7. Таймаути драйвера та політики повторів: налаштуйте їх свідомо; не дозволяйте драйверу «допомагати» вам у створенні бурі повторів.

Жарт №2: Бази даних не «обробляють» сплески. Вони торгуються з ними, і контракт написаний у мілісекундах.

Поширені питання

1) Which one is faster at writes: MariaDB or MongoDB?

Ніхто не «перемагає» універсально. MongoDB може швидко інжестити з ослабленим write concern і правильним shard key. MariaDB може швидко інжестити з group commit і сенсовими індексами. Під суворою стійкістю обидві обмежуються хвостовою латентністю fsync і ампліфікацією записів.

2) What’s the most common reason MariaDB melts during write bursts?

Витрати стійкості коміту (fsync редо/binlog) плюс тиск скидання dirty-сторінок, часто посилені надто великою кількістю вторинних індексів або контенцією гарячих рядків.

3) What’s the most common reason MongoDB melts during write bursts?

Відставання реплікації плюс majority write concern, або чекпоінт/журнал I/O-сплески, коли диск не може утримувати низьку хвостову латентність.

4) Can I “just scale horizontally” to survive bursts?

Іноді так. Шардинг MongoDB може розподілити записи, якщо правильно підібрано ключ. MariaDB можна масштабувати шаріруванням на рівні додатку або кластерами, але мульти-райтерні рішення мають свої обмеження. Горизонтальне масштабування — це проєкт, а не ручка.

5) Is turning off durability acceptable for bursts?

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

6) Should I put redo logs / journal on separate disks?

Розділення може допомогти, якщо контенція є проблемою і у вас справжня ізоляція (а не дві партиції на тому самому пристрої). Частіше кращим рішенням є менше, швидше і передбачуваніше пристрої, ніж складні розкладки.

7) What’s the single best metric for burst survival?

Хвостова латентність стійких записів. Не середнє. Не пікова пропускна здатність. Якщо p99 коміту/журналу погіршився, все вище починає поводитися погано.

8) Does “more RAM” fix burst write problems?

Іноді воно їх відсуває. Для MariaDB більше buffer pool зменшує конкуренцію читань і може вирівняти записи, але також дозволяє накопичувати більше dirty-сторінок. Для MongoDB більше кешу знижує churn, але чекпоінти і журнал все одно вдарять по диску. ОЗП допомагає; вона не скасовує фізику.

9) What about Galera (MariaDB) vs MongoDB replica sets for bursts?

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

10) How do I pick if my workload is “unknown future requirements”?

Якщо вам потрібні реляційні обмеження і складні транзакції — починайте з MariaDB і додавайте документне сховище там, де воно підходить. Якщо ваша предметна область дійсно документно-центрична і ви готові до дизайну шардингу та дисципліни write concern — MongoDB може бути простішою в експлуатації.

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

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

  • Визначте свою політику стійкості (налаштування комітів MariaDB / write concern MongoDB) і задокументуйте її як політику.
  • Виміряйте хвостову латентність fsync/journal на вашому реальному сховищі. Якщо вона непередбачувана — виправляйте платформу перш ніж чіпати плани запитів.
  • Проводьте щомісячні репетиції сплесків: відставання реплік, чекпоінти, переключення, та поведінка клієнтських повторів.
  • Реалізуйте load shedding: обмежуйте конкурентність, додавайте jittered повтори і припиніть вдавати, що таймаути — це стратегія.
  • Зменшуйте записову ампліфікацію: аудитуйте індекси, уникайте гарячих ключів, і тримайте транзакції маленькими й нудними.

Якщо вам потрібен один висновок: MariaDB зазвичай відмовляє повільно і голосно; MongoDB — залежно від топології. Будуйте під режим відмов, який ви зможете оперувати опів на другу ночі, а не під бенчмарк, яким можна похвалитися опівдні.

← Попередня
Журналювання офісного VPN: відстежувати з’єднання та виявляти неавторизованих клієнтів
Наступна →
3dfx: Злет і падіння ігрової легенди

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