Ви не мігруєте бази даних, бо вам нудно. Ви мігруєте тому, що вдарилися в стіну: масштабування записів, затримки між регіонами, операційний оверхед, вибух чисел шардів або дедлайн з комплаєнсу, який не цікавиться вашими вихідними.
MariaDB і TiDB обидві з’являються в розмові «мріємо про MySQL-подібну поведінку, але краще». Маркетингова історія проста: зберегти SQL, отримати масштаб і зменшити біль. Реальність у продакшні складніша: різні режими відмов, різні регулювання і різні способи зіпсувати чергування на викликах. Поговоримо про це.
Що ви насправді обираєте (не просто БД)
«MariaDB vs TiDB» звучить як порівняння продуктів. У продакшні це насправді вибір між двома операційними моделями:
- MariaDB — знайомий однозв’язний движок InnoDB з відпрацьованими схемами реплікації (async replication, semi-sync, GTID, а в деяких розгортаннях — Galera). Його можна експлуатувати нудно й добре. А можна «креативно» й вивчити нові синоніми слова «біль».
- TiDB — розподілений SQL: вузли обчислень (TiDB), вузли зберігання (TiKV) і контрольна площина (PD). Ви купуєте горизонтальне масштабування і HA за дизайном — плюс податок складності розподіленої системи. Кожне «просто» питання стає «який шар і який компонент бреше?»
Ось рішення, яке я просуваю в реальних організаціях:
- Якщо ваш вузький горлечко — один або кілька гарячих primary, але навантаження здебільшого одно-регіональне OLTP, і ви можете масштабувати вертикально та через read replicas, MariaDB залишається важко переможною з точки зору простоти експлуатації.
- Якщо ви вже живете в «шард-пеклі», або вам потрібно масштабувати записи по вузлах з сильною узгодженістю і прийнятною затримкою, TiDB може бути правильним вибором — за умови інвестицій в спостережуваність і SRE-дисципліну.
Одна парафразована ідея від Werner Vogels (CTO Amazon), яка досі справедлива: все ламається, постійно; завдання — спроєктувати так, щоб система продовжувала працювати
(парафразована думка).
Цитата мапується просто: MariaDB — це про інженерію чітких меж відмов навколо переважно однозв’язної істини. TiDB — про інженерування навколо постійних часткових відмов на багатьох вузлах.
Короткі історичні факти, які мають значення
Декілька контекстних пунктів, що змінюють те, як ви експлуатуєте ці системи. Коротко. Конкретно. Корисно.
- MariaDB була форкнута від MySQL у 2009 році після придбання Sun Oracle; це пояснює, чому сумісність — пріоритет і чому «майже як MySQL» — частина ДНК бренду.
- InnoDB став дефолтним движком MySQL роки тому — якщо ваш спадковий додаток досі сподівається на поведінку блокування на рівні таблиці, ви вже граєте на підвищеній складності.
- Galera «multi-master» — насправді синхронна реплікація з сертифікацією. Це не магія. Воно обмінює пропускну здатність записів на глобальне впорядкування і може карати гарячі рядки.
- Архітектура TiDB була натхненна Google Spanner/F1-подібним розділенням (без TrueTime). Важливий аспект — розділення безстанкового SQL і станового KV.
- TiKV використовує Raft-реплікацію. Це означає операції кворуму, питання розміщення лідерів і «один повільний диск може сповільнити регіон» історії.
- PD (Placement Driver) — реальна залежність контрольної площини. Якщо ставитися до неї як до «ще одного сервісу», ви зустрінете її о 3:00 ранку.
- Сумісність з MySQL — рухома ціль для TiDB. Запит, що працює, — не те саме, що запит, який виконується так само. SQL-поверхня ≠ операційна еквівалентність.
- Онлайн-зміни схеми в світі MySQL еволюціонували як механізм виживання. Інструменти й шаблони існують, бо «ALTER TABLE» болюче вже давно.
Архітектура простими словами для опсів: де живуть дракони
MariaDB: один движок, багато способів реплікувати його
Трасування продуктивності MariaDB все ще відчувається як домівка для більшості SRE: CPU, innodb buffer pool, затримки IO, contention на mutex, погані запити, відсутні індекси та лаг реплікації. Коли все горить, зазвичай горить в одному місці.
Навіть у кластерних налаштуваннях (Galera) одиницею болю залишається «вузол бази даних». Його можна виміряти, ізолювати, замінити. Складні моменти:
- Семантика реплікації: async дає лаг і можливу втрату при фейловері; semi-sync зменшує втрати, але додає затримку; Galera означає обробку конфліктів і flow control.
- Зміни схеми: online DDL існує, але не все можна зробити онлайн, і великі таблиці знайдуть гострі краї.
- Масштабування записів: ви масштабуєте записи шляхом vertical scaling, зменшення write amplification або зміни додатку. «Просто додати вузли» — це здебільшого історія про читання.
TiDB: безстанкові SQL-вузли + Raft‑сховище + контрольна площина
TiDB розподіляє вашу базу по шарах:
- TiDB (SQL шар): парсить SQL, планує запити, штовхає роботу вниз і виконує розподілені транзакції.
- TiKV (зберігання): зберігає KV-дані в регіонах, кожен з яких реплікований Raft. Лідери мають значення. Мережа має значення. Диск має значення. Компакація має значення.
- PD: планує регіони, балансірує лідерів, надає таймстемпи і рішення про розміщення.
Саме це розділення дозволяє TiDB масштабувати читання й запис. Це також причина, чому може виникнути «інцидент бази даних», коли CPU в нормі, запити в нормі, а справжній лиходій — один TiKV з жахливим IO, який викликає вибори лідера й повтори транзакцій.
Сухий висновок: розподілена база даних — це база даних плюс курс з розподілених систем, який вам доведеться пройти під час інцидентів. Іспит завжди — із таймером.
Жарт №1: Розподілені бази даних чудові, бо вони перетворюють один повільний диск на командоутворювальний захід між трьома сервісами.
Обіцянки міграції проти того, що ламається першим
Обіцянка: «Він сумісний з MySQL, тож додаток просто працює»
Сумісність проходить через парсинг. Вона не проходить крізь поведінку в продакшні:
- Плани виконання запитів розходяться. Запит, який «добре» працює в MariaDB з одновузловим оптимізатором, може перетворитися на розподілену вечірку повних сканів у TiDB.
- Патерни транзакцій мають більше значення. Довгі транзакції, великі пакетні оновлення та гарячі ключі виявляють contention у Raft і поведінку MVCC.
- Поведінка DDL відрізняється. TiDB підтримує online DDL-патерни, але операційно потрібно планувати навантаження бекуфілу й розклад PD.
Обіцянка: «TiDB прибирає складність шардингу»
Так, але ви міняєте її на іншу складність:
- Hotspotting — це новий шард. Замість «user_id modulo N» ви отримуєте «цей лідер регіону плавиться».
- Планування ємності багаторівневе. Вузли обчислень масштабуются інакше, ніж вузли зберігання. Ваш рахунок і ваше горлечко можуть не співпадати.
- Операційні залежності зростають. Тепер ви експлуатуєте контрольну площину, шар зберігання і безстанкові SQL-вузли.
Обіцянка: «Кластер MariaDB дає HA і масштаб»
HA? Абсолютно, якщо зроблено правильно. Масштаб записів? Обережно. У Galera кожен вузол повинен сертифікувати записи; важкі навантаження на запис можуть страждати від конфліктів і flow control. Async реплікація легко масштабує читання, але записи все ще звужуються через primary.
Обіцянка: «Ми можемо мігрувати з мінімальним даунтаймом»
Можна, але критична робота — не копіювання даних. Це робота зі поведінкової сумісності:
- SQL-моди і неявні перетворення типів
- припущення про рівні ізоляції
- використання недетермінованих функцій
- збережені процедури, тригери та краєві DDL-шаблони
- операційні рукописи: бекапи, відновлення, перемикання, DR
Реалії продакшну: продуктивність, коректність і сон
Реальність продуктивності #1: у затримки з’являються нові підлоги
MariaDB може бути дуже швидкою для однорядкових OLTP-операцій, коли дані в buffer pool і ви не обмежені IO. TiDB додає мережеві стрибки і кворумні коміти. Це не означає, що TiDB «повільний»; це означає, що p99 має іншу фізику.
Якщо ваш продукт вимагає p99 записів менше 5ms у межах однієї AZ, TiDB все ще може працювати, але ви будете нервувати щодо розміщення, локальності лідерів і дизайну транзакцій. Якщо у вас вже p99 = 20–50ms через «чатовий» додаток, наклад TiDB може бути схований під існуючими поганими рішеннями.
Реальність продуктивності #2: hotspots неминучі
У MariaDB гарячі точки — це здебільшого блокування й contention індексів. У TiDB hotspots часто проявляються як:
- Один регіон отримує більшість записів через послідовні ключі
- Лідер зосереджений на одному TiKV
- Криві доступу призводять до вічного «гоніння» PD за балансом
Реальність коректності: семантика «multi-master» інша
Синхронна реплікація Galera означає, що транзакцію потрібно сертифікувати по кластеру; конфлікти виникають під час коміту, і логіка повтору важлива. TiDB забезпечує сильну узгодженість через Raft і MVCC, але розподілені транзакції збільшують вартість contention і довгих транзакцій.
Операційна реальність: бекапи і відновлення — там, де помирає впевненість
Будь‑яка база може зробити бекап. Питання: чи зможете ви відновити швидко, правильно і під тиском? Логічні дампи MariaDB портативні, але можуть бути повільними; фізичні бекапи швидкі, але вимагають дисципліни. Бекапи TiDB включають великий розподілений стан; відновлення повинно враховувати розміщення, навантаження і сумісність версій.
Жарт №2: Бекап — це файл Шредінгера: одночасно дійсний і марний, доки ви не спробуєте відновити.
Швидкий план діагностики
Це послідовність «припиніть дискусії про архітектуру і знайдіть вузьке місце», яку я використовую. Робіть у порядку. Не імпровізуйте, поки не будете мати доказів.
Перше: проблема в додатку, мережі чи базі даних?
- Перевірте розбиття затримки end-to-end. Якщо його немає, витягніть з трасування додатку або хоча б порівняйте DB time vs загальний час запиту.
- Підтвердіть насичення. CPU дотягнутий? IO wait? мережеві ретрансмісії? Якщо нічого не насичено, ви женетеся за contention або планами виконання.
- Підтвердіть шаблон конкурентності. Спайки підключень, thread pool, глибина черг.
Друге: вирішіть, чи вузьке місце — «SQL шар» чи «шар зберігання»
- MariaDB: перевірте InnoDB-метрики, slow log, buffer pool, lag реплікації.
- TiDB: перевірте TiDB CPU і тривалість запитів, потім TiKV IO/CPU і raftstore-метрики, потім PD scheduling і баланс лідерів.
Третє: класифікуйте режим відмови
- Регресія плану: раптовий стрибок латентності після деплою/зміни схеми.
- Contention: очікування блокувань, deadlock, raft write stalls, гарячі регіони.
- Ємність: затримки диска, борг компакації, промахи buffer pool, stalls RocksDB у TiKV.
- Контрольна площина: PD недоступний, scheduling застряг, проблеми з метаданими.
- Реплікація/фейловер: лаг, вибори, механізми запобігання split-brain.
Четверте: виберіть найшвидший важіль «зменшення навантаження», поки діагностуєте
- Обмежте швидкість найгарячіших кінцевих точок.
- Вимкніть дорогі фоновые задачі.
- Тимчасово збільште таймаути пулів підключень, щоб уникнути thundering herd.
- У TiDB розгляньте переміщення лідерів з хворого TiKV і зменшення тиску на hotspot.
Практичні завдання (команди, виводи, рішення)
Нижче — реальні завдання, які можна виконувати під час планування міграції, налагодження продуктивності та реагування на інциденти. Кожне містить: команду, приклад виводу, що це означає і яке рішення прийняти.
Завдання 1: Підтвердити версію MariaDB, змінні сервера та основи движка
cr0x@server:~$ mysql -h mariadb01 -uroot -p -e "SELECT VERSION(); SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; SHOW VARIABLES LIKE 'log_bin';"
Enter password:
VERSION()
10.11.6-MariaDB-1:10.11.6+maria~ubu2204
Variable_name Value
innodb_buffer_pool_size 17179869184
Variable_name Value
log_bin ON
Значення: У вас MariaDB 10.11, buffer pool 16GiB, binlog увімкнено.
Рішення: Якщо ви покладаєтеся на CDC або async репліки, binlog повинен залишатися увімкненим. Якщо ви IO‑зв’язаний і не потребуєте binlog, це велика розмова — не «оптимізуйте» шлях відновлення.
Завдання 2: Виявити топ подій очікування та біль від блокувань у MariaDB
cr0x@server:~$ mysql -h mariadb01 -uroot -p -e "SHOW ENGINE INNODB STATUS\G" | sed -n '1,120p'
Enter password:
*************************** 1. row ***************************
Type: InnoDB
Name:
Status:
=====================================
2025-12-30 10:41:23 0x7f5a2c1ff700 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 28 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 714 srv_active, 0 srv_shutdown, 1082 srv_idle
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 24417
--Thread 140025024026368 has waited at row0lock.cc line 1134 for 12.00 seconds the semaphore:
Значення: Потоки чекають на рядкові блокування; ймовірно contention або транзакція, що тримає блокування занадто довго.
Рішення: Знайдіть блокуючу транзакцію (наступне завдання) і вирішіть: вбити її, зменшити розмір батча, додати індекс або переписати патерн оновлення.
Завдання 3: Виявити довготривалі транзакції в MariaDB
cr0x@server:~$ mysql -h mariadb01 -uroot -p -e "SELECT trx_id, trx_started, trx_mysql_thread_id, trx_query FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 5\G"
Enter password:
*************************** 1. row ***************************
trx_id: 9A3F2B11
trx_started: 2025-12-30 10:12:01
trx_mysql_thread_id: 18841
trx_query: UPDATE orders SET status='CLOSED' WHERE customer_id=412993;
Значення: Транзакція відкрита ~30 хвилин. Вона може блокувати purge і інші писачі.
Рішення: Якщо безпечно — вбити сесію і виправити логіку додатку, щоб уникати довгих транзакцій (частіше комітити, менші батчі).
Завдання 4: Підтвердити стан реплікації і лаг у MariaDB
cr0x@server:~$ mysql -h mariadb-replica01 -uroot -p -e "SHOW SLAVE STATUS\G" | egrep "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master|Using_Gtid"
Enter password:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 37
Using_Gtid: Slave_Pos
Значення: Репліка здорова, але відстає на ~37 секунд.
Рішення: Якщо ваш RTO/RPO не може терпіти 37 секунд, потрібні semi-sync, кращий хостинг, зменшення навантаження на записи або інша топологія.
Завдання 5: Перевірити формат binlog для припущень міграції/CDC
cr0x@server:~$ mysql -h mariadb01 -uroot -p -e "SHOW VARIABLES LIKE 'binlog_format';"
Enter password:
Variable_name Value
binlog_format ROW
Значення: Увімкнено row-based binlog; добре для багатьох CDC-пайплайнів.
Рішення: Залишайте ROW для коректності, якщо немає протестованої причини інакше. Statement-based binlog плюс недетерміновані запити — шлях до «креативності репліки».
Завдання 6: Висвітлити повільні запити в MariaDB (з реальними доказами)
cr0x@server:~$ sudo tail -n 20 /var/log/mysql/slow.log
# Time: 2025-12-30T10:38:13.512345Z
# User@Host: app[app] @ 10.20.3.14 []
# Query_time: 2.871 Lock_time: 0.004 Rows_sent: 25 Rows_examined: 1820031
SELECT * FROM orders WHERE created_at >= '2025-12-01' ORDER BY created_at DESC LIMIT 25;
Значення: Великий скан (1.8M рядків обстежено) для повернення 25 рядків. Класичний випадок відсутнього індексу або неправильного патерну доступу.
Рішення: Додайте покриваючий індекс (наприклад, на created_at плюс поля фільтра), або переробіть запит, щоб уникнути сортування великих діапазонів.
Завдання 7: Перевірити використання індексу через EXPLAIN у MariaDB
cr0x@server:~$ mysql -h mariadb01 -uroot -p -e "EXPLAIN SELECT * FROM orders WHERE created_at >= '2025-12-01' ORDER BY created_at DESC LIMIT 25\G"
Enter password:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: orders
type: ALL
possible_keys: idx_created_at
key: NULL
rows: 1900000
Extra: Using where; Using filesort
Значення: Повний скан таблиці і filesort; індекс не використовується.
Рішення: Виправити індекс або запит. Якщо індекс існує, але не використовується, перевірте невідповідність колації/типів, функції над колонкою або погану статистику кардинальності.
Завдання 8: Снімок здоров’я кластера TiDB (перевірка контрольної площини)
cr0x@server:~$ tiup ctl:v8.5.0 pd -u http://pd01:2379 store
{
"count": 3,
"stores": [
{ "store": { "id": 1, "address": "tikv01:20160", "state_name": "Up" } },
{ "store": { "id": 2, "address": "tikv02:20160", "state_name": "Up" } },
{ "store": { "id": 3, "address": "tikv03:20160", "state_name": "Up" } }
]
}
Значення: PD доступний; TiKV stores Up.
Рішення: Якщо PD не відповідає швидко, перестаньте звинувачувати SQL. Стабілізуйте PD/кворум спочатку; від нього залежить все.
Завдання 9: Виявити гарячі регіони в TiDB/TiKV (де ховаються «шарди»)
cr0x@server:~$ tiup ctl:v8.5.0 pd -u http://pd01:2379 hot read
{
"as_leader": [
{ "region_id": 74219, "store_id": 2, "hot_degree": 97, "flow_bytes": 183274112 }
]
}
Значення: Store 2 — лідер для дуже гарячого регіону. Очікуйте нерівномірної латентності та CPU на цьому вузлі.
Рішення: Дослідіть патерн доступу (послідовні ключі, time-series вставки або один орендар). Розгляньте спліт регіонів, зміну дизайну ключа або переміщення лідерів як тимчасову міру.
Завдання 10: Перевірити баланс лідерів і scheduling у TiDB (чи PD виконує свою роботу?)
cr0x@server:~$ tiup ctl:v8.5.0 pd -u http://pd01:2379 scheduler show
[
"balance-leader-scheduler",
"balance-region-scheduler",
"balance-hot-region-scheduler"
]
Значення: Очікувані шедулери увімкнені.
Рішення: Якщо balance-hot-region-scheduler відсутній/вимкнений, гарячі точки затягнуться. Увімкнюйте його лише якщо розумієте побічні ефекти для стабільності під пик навантаження.
Завдання 11: Виявити повтори транзакцій і latch contention з SQL-шару TiDB
cr0x@server:~$ mysql -h tidb01 -P4000 -uroot -e "SHOW STATUS LIKE 'tidb_txn_retry%'; SHOW STATUS LIKE 'tidb_server_execute%';"
Variable_name Value
tidb_txn_retry_total 1842
Variable_name Value
tidb_server_execute_duration_seconds_count 1298821
Значення: Нетривіальні повтори транзакцій. Часто це contention, конфлікти або повільні відповіді зі зберігання.
Рішення: Якщо повтори зростають під час інцидентів, пріоритет — перевірка hotspot і здоров’я зберігання, а не дрібні SQL‑тюнинги.
Завдання 12: Підтвердити здоров’я диска TiKV і IO wait на підозрілих вузлах
cr0x@server:~$ ssh tikv02 "iostat -x 1 3 | tail -n +4"
Device r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await %util
nvme0n1 210.4 488.7 12.1 44.8 121.3 8.72 15.90 98.7
Значення: Диск майже насичений (%util ~99) з підвищеним await. TiKV на цьому вузлі відповідатиме повільно; Raft-лідери тут будуть шкодити всьому кластеру.
Рішення: Перемістіть лідерів/регіони від цього store і виправте сховище (здоров’я NVMe, файлову систему, noisy neighbor, тиск компакацій). Якщо це хмарний том — перевірте burst credits і обмеження пропускної здатності.
Завдання 13: Валідовати план запиту TiDB, а не лише текст запиту
cr0x@server:~$ mysql -h tidb01 -P4000 -uroot -e "EXPLAIN ANALYZE SELECT * FROM orders WHERE created_at >= '2025-12-01' ORDER BY created_at DESC LIMIT 25;"
+---------------------------+---------+---------+-----------+----------------------------+
| id | estRows | actRows | task | operator info |
+---------------------------+---------+---------+-----------+----------------------------+
| TopN_5 | 25.00 | 25 | root | order by:created_at, limit |
| └─TableFullScan_7 | 1.90e+6 | 1.82e+6 | cop[tikv] | keep order:false |
+---------------------------+---------+---------+-----------+----------------------------+
Значення: У TiKV відбувається повний скан. Розподілена система сумлінно робить неправильну роботу.
Рішення: Додайте правильний індекс або перепишіть запит. Якщо сканувати потрібно, плануйте це у позапік і ізолюйте через контролі ресурсів; не дозволяйте аналітиці маскуватися під OLTP.
Завдання 14: Перевірити використання диска MariaDB і ріст перед cutover
cr0x@server:~$ sudo du -sh /var/lib/mysql; sudo df -h /var/lib/mysql
182G /var/lib/mysql
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p2 500G 412G 63G 87% /var/lib/mysql
Значення: Ви на 87% використання диска. Це не «в порядку». Це «один rebuild індексу від того, щоб розбудити команду».
Рішення: Перед запуском інструментів міграції розширіть диск або очистьте простір. Міграції підсилюють тимчасові потреби простору (DDL, backfill, логи, снимки).
Три корпоративні міні-історії з бійниці
Міні-історія 1: Інцидент через неправильне припущення
Компанія була в середині міграції з MariaDB на TiDB. План був консервативним: dual-write деякий час, читати з MariaDB, потім переключити читання на TiDB. Команда пишалася своїм тестуванням сумісності SQL; інтеграційний набір пройшов; дашборди були зелені.
Вони перемкнули невеликий відсоток трафіку читань на TiDB. Протягом години p99 латентність подвоїлася для кількох кінцевих точок. Нічого драматичного, просто повільне кровотечі, що руйнує конверсійні воронки і змушує продукт-менеджерів дізнатися фразу «регресія бази даних».
Припущення: «Якщо запит індексований в MariaDB, він поводитиметься подібно в TiDB». Реальність: запит використовував композитний індекс у MariaDB через конкретний патерн селективності, але план TiDB обрав повний скан при тій розподіленості. Технічно SQL коректний, функціонально результати вірні — просто операційно неправильно.
Під час розбору інциденту болючий урок був не в «TiDB поганий». Вони не побудували gate для валідації планів. Тестували коректність, а не продуктивність. Виправлення було банальне: захоплювати топ‑запити, виконувати EXPLAIN ANALYZE в обох системах і блокувати міграцію, коли план змінюється на дорогий без явного дозволу.
Що врятувало їх від повторення помилки — одне правило: якщо запит торкається більше X рядків або виконує повний скан в TiDB, йому потрібен індекс, перепис або план ізоляції ресурсів. Ніяких винятків «але раніше так було нормально».
Міні-історія 2: Оптимізація, яка обернулася проти
Інша команда тримала MariaDB з репліками і мала періодичну звітну задачу, яка робила великі скани діапазонів. Хтось вирішив «оптимізувати» її, перевівши звіт на репліку і збільшивши паралелізм. Задача закінчилася швидше. Усі тихо аплодували в Slack.
Через тиждень стався фейловер під час мережевого флапу. Промотована репліка відставала більше, ніж команда усвідомлювала, бо звітна задача нагружала IO і повільно застосовувала реплікаційні події. Фейловер пройшов, але вони протягом довшого часу віддавали трохи застарілі дані — фінанси це помітили, а помічання від фінансів дає запрошення в календар.
Корінь проблеми не в «звітування на репліці». Він в поєднанні: збільшене IO навантаження, менше запасу для застосування реплікації і процес фейловера, що не контролював RPO («не промотувати, якщо lag > поріг»).
Виправлення було не героїчним. Вони обмежили швидкість звітної задачі, додали спеціалізовану аналітичну репліку з іншим обладнанням і змусили автоматизацію фейловера перевіряти лаг реплікації явно. Урок: оптимізації продуктивності, що ігнорують шляхи фейловера, — це просто outages з кращим PR.
Міні-історія 3: Нудна, але правильна практика, що врятувала день
Компанія, яка працювала на TiDB, мала непомітну практику, яку ніхто не любив: квартальні drills відновлення. Не «ми виконали команду бекапу». Реальні відновлення в ізольоване середовище з валідаційними запитами і заміром по часу runbook.
І сталася помилка людини в автоматизаційному скрипті, що видалила не ту таблицю в продакшні. Зміна була швидко помічена, але дані також швидко зникли. Паніка намагалася зайняти місце.
Вони виконали runbook. Відновили в новий кластер, перевірили кількість рядків і контрольні суми для критичних таблиць, після чого перенаправили додаток на постраждалий набір даних. Це було не миттєво, але контрольовано. Інцидент рахували хвилинами простою, а не екзистенційною панікою.
Postmortem був нудний. Без злодія. Без дива. Просто доказ того, що нудні дисципліни — drills відновлення, чіткі RTO/RPO і протестовані процедури cutover — кращі за хитрощі. Команда зберегла свої вихідні, що є найрідкіснішим KPI.
Типові помилки (симптом → корінь проблеми → виправлення)
1) «TiDB повільний» (p95/p99 зростає після міграції)
Симптом: Читання й записи обидва повільні; CPU не завантажений; додаток бачить повтори/таймаути.
Корінь проблеми: Розміщення між зонами/регіонами, лідери не локальні або затримка диска на підмножині TiKV вузлів. Розподілені коміти платять за найповільнішого учасника кворуму.
Виправлення: Забезпечити локальність (labels/placement rules), підтвердити розподіл лідерів і виправити повільні вузли зі сховищем. Виміряти latency raft commit і disk await.
2) Репліка MariaDB «раптом» відстає під пік
Симптом: Seconds_Behind_Master стрибає; читання стають застарілими; ризик фейловера зростає.
Корінь проблеми: Насичення IO на репліці, довгі транзакції на primary створюють великі сплески binlog або однопотокове застосування залежно від конфігурації/навантаження.
Виправлення: Зменшити write amplification (індекси, розмір батчів), забезпечити IO headroom для репліки, розглянути паралельну реплікацію де можливо, і встановити gates на фейловер залежно від lag.
3) Пропускна здатність Galera падає при зростанні конкурентності записів
Симптом: Додавання вузлів не додає пропускної здатності записів; з’являються конфлікти і flow control; латентність зростає.
Корінь проблеми: Конфлікти сертифікації на гарячих рядках, занадто багато одночасних писачів або великі транзакції, що викликають координаційні витрати по всьому кластеру.
Виправлення: Зменшити write contention (зміни схеми, дизайн ключів), розбити транзакції, прикріпити записи до одного вузла (якщо прийнятно) або перестати вважати Galera панацеєю для масштабування записів.
4) TiDB hotspot, що ніколи не зникає
Симптом: Один TiKV вузол залишається гарячим; PD «балансує», але біль лишається; повтори транзакцій ростуть.
Корінь проблеми: Послідовні ключі або монотонні вставки, що створюють регіональні hotspot; недостатній pre-split регіонів; скривлення навантаження по орендарях.
Виправлення: Змінити дизайн ключів (уникати монотонних первинних ключів для гарячих таблиць), включити/pre-split для гарячих таблиць, ізолювати орендарів і обережно використовувати hotspot scheduling.
5) Міграція пройшла, але через тиждень з’явилися баги коректності
Симптом: Інколи відсутні/подвійні рядки, дивне округлення, відмінності чутливості до регістру або часові зони-загадки.
Корінь проблеми: Різниці в SQL mode, колації, неявні перетворення або залежність додатку від невизначеної поведінки.
Виправлення: Закріпити SQL modes і колації, додати перевірки валідації даних і усунути «рядок‑в‑ціле число» магію та неоднозначності часових зон у додатку.
6) Бекап існує, але відновлення не проходить
Симптом: Відновлення займає значно більше часу, ніж планувалося, або падає через права, відсутні binlog або несумісність версій.
Корінь проблеми: Непротестований шлях відновлення, непослідовні снапшоти або недостатньо забезпечене середовище відновлення.
Виправлення: Регулярні drills відновлення, документовані runbook і планування пропускної здатності для відновлення (мережа + диск + CPU).
Контрольні списки / поетапний план
Чекліст рішення: чи залишатися на MariaDB?
- Ваше навантаження на записи поміщається в один primary з запасом після розумного тюнінгу.
- Ви можете терпіти лаг реплік або можете прийняти компроміс semi-sync.
- Ваш ключовий біль — якість запитів/індексів, а не кількість шардів.
- Ви хочете найпростішу модель відмов і мінімальну операційну поверхню.
Чекліст рішення: чи переходити на TiDB?
- Вам потрібне масштабування записів поза межі одного вузла без шардингу в додатку.
- Ви готові інвестувати в спостережуваність: трасування, метрики по компонентах і управління ємністю.
- Ви приймаєте вищу базову латентність в обмін на масштаб і HA.
- Ви готові переробити гарячі ключі і патерни транзакцій.
Поетапний план міграції, що переживе контакт з продакшном
- Інвентар навантаження: топ‑запити за латентністю і частотою, топ‑таблиці за записами, найбільші таблиці за розміром.
- Закріпіть семантику: SQL mode, timezone, collation, очікування ізоляції.
- Плануйте індекси першими: валідируйте плани запитів у цільовій системі для топ‑N запитів.
- Побудуйте валідацію даних: counts, checksums по партиціям/діапазонам та бізнес‑інваріанти.
- Дизайн cutover: dual-write vs CDC; визначити rollback.
- Практикуйте фейловер і відновлення: для обох систем перед перемиканням у продакшн.
- Зробіть dark launch: mirror reads або shadow traffic; порівнюйте результати й латентності.
- Повільне нарощування: 1% → 5% → 25% → 50% з явними критеріями прийняття.
- Заморозьте ризикові зміни: ніяких великих рефакторів схеми під час ramp, якщо ви не любите драму.
- Документуйте операційну відповідальність: хто пейджить для PD? хто для повільних компакацій? хто володіє gates на схеми?
Чекліст runbook: як виглядає «готовий до проду»
- Завдання бекапу працює з моніторингом успіху і відомим часом відновлення.
- Drill відновлення пройдено за останні 90 днів з зафіксованими таймінгами.
- Існують дашборди для кожного шару (SQL, зберігання, контрольна площина) з фокусом на p95/p99.
- Пороги алертів прив’язані до впливу на користувача (латентність, помилки), а не до марнославних метрик.
- Ємність запасу: диск, IO і CPU, плюс місце для обслуговування/компакації.
FAQ
1) Чи є TiDB «drop-in заміною» для MariaDB/MySQL?
Для багатьох додатків це достатньо, щоб почати тестувати швидко. Але «drop-in» закінчується на продуктивності та операційній поведінці. Розглядайте це як перепис ваших припущень.
2) Чи замінює TiDB потребу в read replicas?
Він змінює модель. Ви масштабуєте TiDB безстанковими SQL-вузлами для пропускної здатності читань, але все ще потрібно планувати домени відмов, розміщення і noisy neighbors.
3) Чи є Galera простішим шляхом до того, що дає TiDB?
Ні. Galera може забезпечити HA і деякі форми multi-node запису, але це не те саме, що розподілений шар зберігання з Raft-реплікацією. Під важким write contention модель сертифікації Galera може шкодити.
4) Які робочі навантаження розкривають TiDB найкраще?
Високі потреби в масштабуванні записів без шардингу в додатку, великі набори даних з горизонтальним зростанням і мішані навантаження, де незалежне масштабування читань і записів допомагає. Також: команди, які вміють експлуатувати розподілені системи.
5) Які робочі навантаження мають залишитися на MariaDB?
Однорегіональне OLTP з прогнозованим зростанням, вимоги до низької латентності і команди, що цінують операційну простоту більше, ніж горизонтальне масштабування записів. MariaDB досі дуже компетентний підсобник.
6) Що першим дивує команди, що переходять на TiDB?
Hotspots. Не через те, що їх не було раніше, а через те, що вони стають видимими як «один регіонний лідер плавиться», а не просто «primary зайнятий».
7) Як думати про різницю в вартості?
MariaDB зазвичай дешевша для помірних навантажень, бо ви купуєте менше вузлів і менше мережі. TiDB часто дорожчий в інфраструктурі, але може бути дешевшим за інженерні зусилля шардингу. Правильна модель включає навантаження на on-call і ризик міграції, не лише кількість вузлів.
8) Чи можу я мігрувати з майже нульовим даунтаймом?
Так, за допомогою CDC/dual-write патернів і акуратного cutover. Ризик даунтайму рідко в копіюванні; це остання миля: дрейф схеми, регресії плану та операційні сюрпризи під час нарощування трафіку.
9) Який найцінніший передміграційний тест?
Запустіть топ 50–200 продакшн-запитів на цільовій системі з даними, що імітують розподіл в продакшні, і порівняйте результати EXPLAIN ANALYZE. Тести коректності не впіймають катастрофи плану.
10) Яка найцінніша операційна звичка для будь‑якої системи?
Drills відновлення. Не опціонально. Не «ми перевірили, що файл існує». Реальні відновлення з валідацією і заміром кроків по часу.
Висновок: наступні кроки, які можна виконати в понеділок
Якщо ви обираєте між MariaDB і TiDB, вирішіть, виходячи з того, що ви готові експлуатувати. MariaDB винагороджує дисциплінарну простоту. TiDB винагороджує команди, які ставлять розподілені системи як перший клас роботи, а не випадкове хобі.
Зробіть наступне:
- Витягніть ваші топ‑запити і порівняйте плани (MariaDB
EXPLAIN, TiDBEXPLAIN ANALYZE). - Запустіть швидкий план діагностики на вашому найгіршому p99 endpoint і класифікуйте вузьке місце.
- Виберіть одну стратегію міграції (CDC/dual-write) і напишіть план rollback до написання cutover-плану.
- Заплануйте drill відновлення. Занесіть у календар. Зробіть його реальним.
Вам не потрібна ідеальна невизначеність. Потрібен контрольований ризик, вимірна продуктивність і система, що ламається так, як ви вже репетирували.