MySQL vs Percona Server: стабільність реплікації — чому команди операцій переходять

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

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

Екосистема MySQL дає варіанти: Oracle MySQL, Percona Server for MySQL, MariaDB і довгий хвіст інструментів. Цей матеріал про вузький, але вирішальний аспект:
стабільність реплікації в продакшні — що ламається, як знайти проблему швидко і чому досвідчені команди операцій часто обирають Percona Server, коли втомилися від несподіванок.

Що команди операцій мають на увазі під «стабільністю реплікації»

«Стабільність реплікації» — це не показник з бенчмарку. Це відсутність драм. У продакшні стабільна реплікація означає:

  • Передбачуваний лаг: ви можете прогнозувати його під навантаженням, і він повертається до базової лінії після сплесків.
  • Безпечна поведінка при перемиканні: підняття репліки до primary не втрачає підтверджені записи та не створює роздвоєної правди.
  • Швидка ясність щодо кореня проблеми: коли щось іде не так, ви можете визначити, чи причина у майстрі, мережі, relay логах, аплаєрі чи сховищі.
  • Операційний запас: ви можете виконувати зміни схеми, бекапи та обслуговування без того, щоб реплікація перетворювалася на місце злочину.
  • Гарантії консистентності, які можна пояснити: інженерам та аудиторам без танців навколо пояснень.

Стабільність — це не просто «реплікація працює». Це «реплікація нудна». Нудність — це функція, яку ви хочете, коли бізнес на зв’язку.

MySQL vs Percona Server на практиці (не маркетинг)

Сумісність: чому Percona взагалі в розмові

Percona Server for MySQL у практичному сенсі є drop-in заміною: той самий протокол, той же SQL-шар, той самий модель реплікації і загалом та сама поверхня конфігурацій.
Це важливо, бо «перехід» в операціях зазвичай — контрольована заміна пакета, а не переписування всього.

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

Стабільність реплікації часто маскує проблему спостережності

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

Операційна відмінність Percona часто не в якомусь магічному алгоритмі реплікації. Це:

  • Більше відкритих внутрішніх лічильників і діагностик у вигляді, дружньому до продакшену.
  • Фічі та патчі, спрямовані на продуктивність під конкурентністю (саме там народжується лаг реплікації).
  • Першокласна інтеграція з набором інструментів: Percona Toolkit (pt-heartbeat, pt-table-checksum) і Percona XtraBackup.

Де насправді виграється стабільність: три пляшки горла

Реплікація ламається в трьох місцях:

  1. Шлях коміту на джерелі: груповий коміт binlog, поведінка fsync, параметри надійності, різкі хвилі записів.
  2. Транспорт і relay: мережеві коливання, втрата пакетів, I/O relay логів, насичення диска на репліках.
  3. Шлях аплаювання на репліці: SQL-потік (або applier workers), випадковий I/O, конкуренція за блокування, залежності транзакцій, інтенсивні DDL.

Percona Server зазвичай дає більше видимості та налаштувальних гачків навколо цих вузьких місць. Це не звільняє вас від розуміння їх.

Мій операційний, але думка

Якщо у вас один primary і одна репліка, і ви ставитесь до реплікації як до побічної думки, MySQL підійде — поки не піде. Якщо реплікація є частиною вашого плану доступності,
аналітичного конвеєра або розумового здоров’я on-call, вам потрібні кращі діагностики й безпечніші практики. Саме тут Percona Server часто відпрацьовує свою ціну.

Не перемикайтеся за відчуттями. Перемикайтеся тому, що можете показати розрив у стабільності або операційності, який потрібно закрити.

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

  • Реплікація починалася як statement-based, що було швидко, але крихко; row-based реплікація стала вибором «я за коректність» для багатьох навантажень.
  • MySQL 5.6 зробив GTID мейнстримом для користувачів MySQL, перетворивши відкат з «арифметики позицій» на «ідентичність транзакції», з новими способами нашкодити собі.
  • Багатопотокова реплікація з’явилася, щоб вирішити головну проблему: один SQL-потік не встигає за сучасними швидкостями запису.
  • Семісинхронна реплікація була введена, щоб зменшити втрати даних при переключенні, але її поведінка під латентністю може здивувати команди, які трактують її як синхронний кворум.
  • Crash-safe реплікація покращувалася з часом; старі конфігурації могли втрачати стан relay логів і вимагали ручної операції після краху.
  • Percona Server історично постачав додаткову інструментацію (лічильники статусу, доповнення до slow query, фічі продуктивності), орієнтовані на операторів, а не тільки на розробників.
  • Percona Toolkit став де-факто «швейцарським ножем DBA» у багатьох командах: виявлення чексемів, онлайн-зміни схеми та вимірювання лагу через heartbeat.
  • XtraBackup змінив операції з репліками, зробивши гарячі фізичні бекапи практичними для великих InnoDB наборів, скоротивши час відновлення і зменшивши борг реплікації.

Реальні режими відмов реплікації

1) «Лаг», який насправді — затримка коміту на джерелі

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

2) Насичення I/O relay логів на репліках

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

3) Вузькі місця аплай-потоку: залежності і «гарячі» рядки

Мультипотокова реплікація допомагає, але тільки коли транзакції можна паралелізувати. Якщо навантаження б’є по тих самих рядках, тих самих сторінках індексу
або одній таблиці, аплаєр фактично сериалізований. Це часто виглядає як «реплікація не використовує CPU», бо вона чекає на блокування або I/O.

4) DDL і metadata lock

Один невинний ALTER TABLE на джерелі може блокувати запис, блокувати ротацію binlog або призвести до зупинки аплаювання на репліці, поки metadata lock не зникне.
«Online DDL» — не релігія; це набір компромісів.

5) Недетермінованість і пастки statement-based реплікації

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

6) GTID і помилкові транзакції

GTID спрощує відновлення після відмови, але карає за недбале керування записами. Якщо «репліка» приймає записи (навіть коротко), ви можете створити GTID-набори, що ускладнять повторне приєднання.
Система каже вам правду: топологія більше не лінійна.

Жарт №1: Реплікація — як стосунки на відстані — якщо ви припините спілкуватися, хтось зрештою вигадає свою правду.

План швидкої діагностики: перший / другий / третій

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

Перший: репліка зупинилась, дрейфує чи просто відстає?

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

Другий: чи джерело стабільно продукує binlog?

  • Шукайте затримки комітів: fsync, тиск у redo логу, налаштування синхронізації binlog, затримка диска.
  • Перевірте, чи груповий коміт binlog ефективний або зруйнований налаштуваннями чи характером навантаження.
  • Підтвердіть, що джерело не блокується через DDL, metadata lock або довгі транзакції.

Третій: чи репліка обмежена I/O, блокуваннями чи паралельністю?

  • Перевірте I/O relay логів та насичення диска на репліці.
  • Перевірте використання applier worker-ів і стан координатора.
  • Огляньте InnoDB history list length і відставання purge (тиск undo робить все гірше).
  • Визначте «гарячі» таблиці та запити, що аплаяться повільно.

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

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

Команди нижче припускають типову Linux-інсталяцію з локальним MySQL-сумісним сервером і налаштованою реплікацією. Підлаштовуйте облікові дані та сокети під своє середовище.
Суть не в точних заклинаннях; суть у робочому процесі: команда → інтерпретація виводу → ухвалення рішення.

Задача 1: Перевірити здоров’я потоків реплікації (найшвидший тест «воно померло?»)

cr0x@server:~$ mysql -uroot -p -e "SHOW REPLICA STATUS\G" | egrep -i "Replica_IO_Running|Replica_SQL_Running|Last_SQL_Error|Last_IO_Error|Seconds_Behind_Source|Retrieved_Gtid_Set|Executed_Gtid_Set"
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Seconds_Behind_Source: 7
Last_IO_Error:
Last_SQL_Error:
Retrieved_Gtid_Set: 3E11FA47-71CA-11EE-9A2D-525400123456:1-981233
Executed_Gtid_Set: 3E11FA47-71CA-11EE-9A2D-525400123456:1-981210

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

Рішення: трактувати як «відставання», а не «поломку». Перейти до ідентифікації вузького місця (I/O проти applay проти затримки на джерелі).

Задача 2: Якщо репліка зупинилася — прочитати точну помилку (не гадати)

cr0x@server:~$ mysql -uroot -p -e "SHOW REPLICA STATUS\G" | egrep -i "Replica_SQL_Running|Last_SQL_Errno|Last_SQL_Error|Last_Error_Timestamp"
Replica_SQL_Running: No
Last_SQL_Errno: 1062
Last_SQL_Error: Could not execute Write_rows event on table app.users; Duplicate entry '84219' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.004221, end_log_pos 91827364
Last_Error_Timestamp: 251230 02:14:09

Що це означає: duplicate key — це дрейф даних або помилковий запис на репліці. Це не момент «спробуй пізніше».

Рішення: призупинити автоматичне перемикання; почати аналіз дрейфу (checksum) і перевірку контролю записів на репліці (read_only/super_read_only).

Задача 3: Визначити, де лаг — в I/O-потоку чи в SQL/applier

cr0x@server:~$ mysql -uroot -p -e "SHOW REPLICA STATUS\G" | egrep -i "Seconds_Behind_Source|Replica_IO_State|Slave_SQL_Running_State|Relay_Log_Space|Source_Log_File|Read_Source_Log_Pos|Relay_Source_Log_File|Exec_Source_Log_Pos"
Replica_IO_State: Waiting for source to send event
Slave_SQL_Running_State: Waiting for dependent transaction to commit
Seconds_Behind_Source: 412
Relay_Log_Space: 6832162816
Source_Log_File: mysql-bin.004221
Read_Source_Log_Pos: 98222111
Relay_Source_Log_File: mysql-bin.004219
Exec_Source_Log_Pos: 44112233

Що це означає: I/O-потік встигає («Waiting for source»), але SQL-потік відстає (файл exec старіший; relay space великий).

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

Задача 4: Підтвердити конфіг паралельної реплікації й чи вона працює

cr0x@server:~$ mysql -uroot -p -e "SHOW VARIABLES LIKE 'replica_parallel%'; SHOW STATUS LIKE 'Replica_running%';"
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| replica_parallel_workers      | 8     |
| replica_parallel_type         | LOGICAL_CLOCK |
+-------------------------------+-------+
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| Replica_running           | ON    |
| Replica_running_state     | ON    |
+---------------------------+-------+

Що це означає: налаштовано 8 воркерів; логічний годинник для паралелізму — добрий базовий варіант для багатьох OLTP-навантажень.

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

Задача 5: Виявити вузькі місця воркерів реплікації (аплаєр чекає блокувань або комітів)

cr0x@server:~$ mysql -uroot -p -e "SELECT THREAD_ID, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE FROM performance_schema.replication_applier_status_by_worker;"
+-----------+--------------+-------------------+--------------------+
| THREAD_ID | SERVICE_STATE| LAST_ERROR_NUMBER | LAST_ERROR_MESSAGE |
+-----------+--------------+-------------------+--------------------+
|      1213 | ON           |                 0 |                    |
|      1214 | ON           |                 0 |                    |
|      1215 | ON           |                 0 |                    |
|      1216 | ON           |                 0 |                    |
|      1217 | ON           |                 0 |                    |
|      1218 | ON           |                 0 |                    |
|      1219 | ON           |                 0 |                    |
|      1220 | ON           |                 0 |                    |
+-----------+--------------+-------------------+--------------------+

Що це означає: воркери працюють і не мають помилок. Це не доводить їхню ефективність; доводить, що вони не мертві.

Рішення: корелюйте зі метриками InnoDB і диска; якщо воркери «ON», але лаг зростає, ймовірно ви обмежені I/O або сериалізацією через залежності транзакцій.

Задача 6: Перевірити довгі транзакції на репліці, що блокують аплай (metadata locks, row locks)

cr0x@server:~$ mysql -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"
*************************** 1. row ***************************
trx_id: 924118311
trx_started: 2025-12-30 01:44:02
trx_mysql_thread_id: 23301
trx_query: ALTER TABLE orders ADD COLUMN promo_code VARCHAR(32)

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

Рішення: зупинити конфліктну сесію, перенести DDL на інший час (онлайн-інструменти зміни схеми), і повторно перевірити стан аплаєра.

Задача 7: Виміряти лаг за допомогою pt-heartbeat (Seconds_Behind може брехати)

cr0x@server:~$ pt-heartbeat --user=root --ask-pass --monitor --database=percona --table=heartbeat --host=127.0.0.1 --interval=1
0.00s [  0.00s,  0.00s,  0.00s ]
0.98s [  0.22s,  0.80s,  0.98s ]
4.12s [  1.10s,  3.70s,  4.12s ]

Що це означає: heartbeat показує реальну затримку аплаю; сплески і джиттер вказують на нестабільну пропускну здатність аплая, а не на просто стабільне накопичення беклогу.

Рішення: якщо сплески heartbeat корелюють із затримкою диска або вікнами бекапів — усуньте I/O конкуренцію; якщо з хвилями записів — налаштуйте group commit / паралельний аплай.

Задача 8: Перевірити затримку диска на репліці (I/O-голод — фабрика лагу)

cr0x@server:~$ iostat -x 1 3
Linux 6.5.0 (db-replica-01) 	12/30/2025 	_x86_64_	(16 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          12.44    0.00    4.21   28.77    0.00   54.58

Device            r/s     w/s   rkB/s   wkB/s  await  svctm  %util
nvme0n1         220.0   980.0  8800.0 74200.0  18.40   0.92 97.10

Що це означає: %util близько до 100% і await ~18ms: пристрій насичений. Аплай реплікації буде непостійним.

Рішення: розділити relay логи / datadir, зменшити конкуренцію I/O (бекапи, аналітика) або перейти на швидше сховище. Налаштування не переможуть фізику.

Задача 9: Перевірити тиск флашингу InnoDB (тихий вбивця реплікації)

cr0x@server:~$ mysql -uroot -p -e "SHOW ENGINE INNODB STATUS\G" | egrep -i "Log sequence number|Log flushed up to|checkpoint|pending|history list length|pages flushed"
Log sequence number 228771228911
Log flushed up to   228771110122
Last checkpoint at  228770000000
History list length 142381
pending writes: LRU 0, flush list 87, single page 0
pages flushed: 19872

Що це означає: history list length великий і є pending flush list; purge/flush може відставати під навантаженням записів, спричиняючи застої і лаг.

Рішення: шукати довгі транзакції, налаштувати purge/flush, зменшити «сплесковість»; розглядати зміну innodb_flush_log_at_trx_commit лише з чіткою політикою надійності.

Задача 10: Перевірити binlog і налаштування надійності на джерелі (підозра на затримки комітів)

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

Що це означає: це «надійна» позиція: кожна транзакція флешить redo і binlog. Чудово для безпеки, дорого для латентності.

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

Задача 11: Перевірити користувача реплікації й стан SSL (нестабільна мережа й перевстановлення автентифікації реальні)

cr0x@server:~$ mysql -uroot -p -e "SHOW REPLICA STATUS\G" | egrep -i "Master_SSL_Allowed|Master_SSL_Verify_Server_Cert|SSL|Connect_Retry|Last_IO_Error"
Master_SSL_Allowed: Yes
Master_SSL_Verify_Server_Cert: Yes
Connect_Retry: 60
Last_IO_Error:

Що це означає: SSL увімкнено й сертифікат перевіряється; connect retry розумний; поточних I/O помилок немає.

Рішення: якщо з’являються I/O помилки періодично — корелюйте з мережевими обривами; налаштовуйте таймаути лише після виправлення стабільності транспорту.

Задача 12: Безпечно виявляти дрейф даних за допомогою pt-table-checksum (не «довіряйте» реплікації)

cr0x@server:~$ pt-table-checksum --user=root --ask-pass --host=db-primary-01 --databases=app --replicate=percona.checksums --nocheck-replication-filters
TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
12-30T02:22:01      0      1    128      16       0   0.423 app.users
12-30T02:22:02      0      0   8401      64       0   3.982 app.orders

Що це означає: DIFFS вказує на невідповідність контрольних сум; app.users має дрейф. Це корелює з раніше згаданою помилкою duplicate key.

Рішення: не вважати таку репліку промотабельною; планувати ресинк або цілеспрямоване виправлення за допомогою pt-table-sync після з’ясування причини.

Задача 13: Оцінити ріст relay логів і тиск на диск (часто це просто місця не вистачає)

cr0x@server:~$ du -sh /var/lib/mysql/*relay* 2>/dev/null | sort -h | tail
42G	/var/lib/mysql/relay-bin.000812
42G	/var/lib/mysql/relay-bin.000813
43G	/var/lib/mysql/relay-bin.000814

Що це означає: relay логи роздулися; тиск на диск може спричиняти затримки або майбутній простій.

Рішення: виправте пропускну здатність аплая спочатку; потім перегляньте налаштування очищення relay логів і переконайтесь, що репліка встигає в пікові періоди записів.

Задача 14: Підтвердити, що репліка дійсно лише для читання (запобігти помилковим записам)

cr0x@server:~$ mysql -uroot -p -e "SHOW VARIABLES WHERE Variable_name IN ('read_only','super_read_only');"
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| read_only       | ON    |
| super_read_only | ON    |
+-----------------+-------+

Що це означає: навіть користувачі з SUPER не можуть писати (super_read_only). Це одна з тих налаштувань, яку пропускають лише один раз.

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

Задача 15: Інспектувати пропускну здатність binlog і поведінку ротації (санітарія на стороні джерела)

cr0x@server:~$ mysql -uroot -p -e "SHOW BINARY LOGS;"
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.004219 | 1073741824|
| mysql-bin.004220 | 1073741824|
| mysql-bin.004221 |  812331221|
+------------------+-----------+

Що це означає: binlog-и ротаються на 1GiB; висока частота ротацій може збільшити I/O і метадантичне навантаження, якщо диски повільні або бекапи наївні.

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

Три корпоративні міні-історії з реплікаційного фронту

Міні-історія 1: Інцидент через хибне припущення (GTID робить відкат «автоматичним», правда?)

Середній SaaS працював на MySQL з увімкненим GTID і чистою топологією primary/replica. У них був інструмент відкату, інтегрований з моніторингом.
Команда вірила, що GTID означає, ніби відкат тепер — детермінована кнопка: підніми репліку з найбільш виконаними GTID, перемапай додаток і йдемо далі.

Під час невеликої мережевої події одна репліка тимчасово втратила зв’язок з primary. Моніторинг помітив «реплікація зупинилась» і спрацював тригер промоції.
Новий primary піднявся, але частина трафіку досі йшла до старого primary, бо припущення про TTL DNS не відповідало реальності. Записи з’являлися в обох місцях.
Ніхто не помітив одразу, бо обидва виглядали «здоровими» з точки зору додатка.

Наступна година була дорогою наукою про GTID-набори. Коли вони намагалися приєднати старий primary як репліку, він відмовився: існували errant транзакції з обох сторін.
Вони тепер стали щасливими власниками двох різних істин. Менеджери інженерії хотіли швидкого злиття. База даних не переймалася їхніми почуттями.

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

Пізніше вони перейшли на Percona Server — не тому, що це б попередило цю помилку, а тому, що хотіли кращої видимості та дисципліни інструментів навколо стану реплікації.
Справжня зміна була культурною: відкат — це процедура, а не рефлекс.

Міні-історія 2: Оптимізація, що повернулася бумерангом (швидкі коміти, повільне все інше)

Інша компанія ганялася за латентністю. Хтось запропонував послабити надійність: встановити sync_binlog=0 і innodb_flush_log_at_trx_commit=2.
Аргумент був переконливий: менше fsync, краща пропускна здатність, менше відставання реплік, бо джерело «працюватиме плавніше».

Воно йшло плавніше. Аж поки хост не перезавантажили під час оновлення ядра і щось пішло трохи не за сценарієм. Джерело відновилося, але binlog і InnoDB redo не вирівнялися ідеально.
Реплікація не зупинилася; вона аплайнула те, що могла. Проблема була гірша: набори даних мали тонкі невідповідності і відсутні транзакції відносно того, що додаток підтвердив.

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

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

Жарт №2: Вимкнути fsync, щоб «полагодити» реплікацію — це як зняти сигнал тривоги, щоб зупинити писк — тихо, поки не настане пам’ятний момент.

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

Фінтех-компанія працювала на Percona Server з суворою звичкою: щокварталу вони перебудовували репліку з нуля за допомогою Percona XtraBackup.
Не заради розваги — щоб підтримувати runbook в актуальному стані і доводити, що бекапи придатні.

Одного дня одна репліка почала кидати помилки duplicate key. Початковий інстинкт — «пропустити» подію, щоб репліка знову запрацювала.
Але їхня політика забороняла пропуск без порівняння контрольних сум і інцидентного тикета. Люди бурчали. Політика витримала.

Вони запустили pt-table-checksum і виявили дрейф, обмежений ним небагатьма таблицями, пов’язаними з legacy batch job.
Batch job випадково писав у репліку протягом вихідних. read_only був увімкнений, але super_read_only — ні, і job використовував привілейований акаунт.

Оскільки вони тренували перебудови, реакція була чистою: відновити уражену репліку, оновити привілейовані облікові, увімкнути super_read_only і додати захисний механізм у розгортання job.
Бизнес-імпакт був мінімальний. On-call встиг поїсти, поки обід був ще теплий. Ось як виглядає «нудно», коли це працює.

Поширені помилки: симптом → корінь → виправлення

1) Симптом: Seconds_Behind_Source різко стрибає, потім відновлюється

Корінь: насичення I/O на репліці (relay логи + InnoDB flush + читання бекапів) або сплески комітів на джерелі.

Виправлення: ізолюйте I/O (окремі томи якщо можливо), плануйте бекапи не в піки, перевірте тиск флашингу та вимірюйте реальний лаг через pt-heartbeat.

2) Симптом: SQL-потік репліки зупинився з errors duplicate key

Корінь: дрейф даних (помилкові записи, недетермінований SBR, ручні правки на одній ноді).

Виправлення: не пропускайте бездумно; робіть checksums, знайдіть шлях запису, увімкніть super_read_only, потім ресинкуйте через rebuild або цілеспрямований sync.

3) Симптом: Реплікація «працює», але читаючі запити отримують застарілі дані

Корінь: ви читаєте з відстаючої репліки без консистентності сесії, або Seconds_Behind_Source вводить в оману (зсув часу, відсутність heartbeat).

Виправлення: додайте вимірювання heartbeat, реалізуйте маршрутизацію read-your-writes (GTID-aware, підтримка проксі) або обмежте читання з реплік для критичних шляхів.

4) Симптом: Відкат спрацював, але старий primary не може приєднатись

Корінь: errant GTID через записи на обох нодах або неналежне фанування.

Виправлення: впровадьте fencing (VIP/проксі, правила фаєрволу), зробіть репліки лише для читання і відновлюйте ноди, а не намагайтеся панічно коригувати GTID-набори.

5) Симптом: Реплікація зупиняється на DDL або чекає вічно

Корінь: contention метадантичних блокувань або довга транзакція, що заважає завершенню DDL.

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

6) Симптом: Репліка не встигає, навіть з великою кількістю applier workers

Корінь: транзакції не паралелізуються (гарячі рядки/таблиці) або реальне обмеження — I/O.

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

7) Симптом: «IO thread reconnecting» і періодичні зупинки

Корінь: нестабільність мережі, проблеми з DNS, затримки TLS-ренегоціації або надмірно агресивні таймаути.

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

8) Симптом: Репліки відстають під час бекапів

Корінь: читання бекапів насичує сховище або процес бекапу конкурує за CPU і кеш.

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

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

Контрольний список A: Якщо ваша операційна ціль — «безпечне переключення», зробіть це в такому порядку

  1. Забезпечте захист від записів на репліках: встановіть read_only=ON і super_read_only=ON на всіх репліках через конфігураційний менеджмент.
  2. Уніфікуйте режим GTID по всьому кластеру (якщо ви його використовуєте): узгоджені gtid_mode і enforce_gtid_consistency.
  3. Впровадьте fencing при відключенні: доведіть, що старий primary недоступний для записів (проксі/VIP/фаєрвол), а не просто «помічений як нездоровий».
  4. Зробіть лаг видимим: вимірювання через heartbeat, а не тільки Seconds_Behind_Source.
  5. Репетируйте процедури повернення в кластер: практикуйте відновлення ноди й її чисте повторне введення.
  6. Визначте позицію надійності явно: документуйте, чи ви використовуєте sync_binlog=1 і innodb_flush_log_at_trx_commit=1, і чому.

Контрольний список B: Якщо ваша ціль — «менше лагу під навантаженням», почніть тут

  1. Виміряйте вузьке місце: джерело комітів, транспорт, relay I/O чи аплай?
  2. Виправте затримку сховища першочергово: якщо репліка на 95–100% завантаженні диска, у вас не проблема налаштувань реплікації, а проблема бюджету I/O.
  3. Використовуйте ROW binlog format якщо немає чіткої причини інакше.
  4. Увімкніть розумну паралельну реплікацію і перевірте її ефективність (статистика воркерів, а не тільки налаштування).
  5. Зменшіть «гарячі» точки: перепишіть той запит, що оновлює один рядок 10 000 разів на хвилину. Ви знаєте який.
  6. Контролюйте вікна важкого обслуговування: бекапи, зміни схеми, аналітичні запити — не нагромаджуйте їх у пік записів.

Контрольний список C: Покроковий план для переходу на Percona Server (мінімізувати ризик)

  1. Виберіть пілотний кластер, де проблеми реплікації видимі, але бізнес-ризик керований.
  2. Узгодьте версії уважно (major/minor) і перевірте сумісність реплікації в staging з трафіком, схожим на продакшен.
  3. Замініть спочатку репліки: поміняйте пакети на репліці, дайте їй відреплікуватися, валідуйте через checksums і читання додатка.
  4. Промотуйте Percona-репліку під час планової події (з повним fencing) і зробіть її primary.
  5. Оновіть решту нод по черзі; майте чистий план відкату (відновлення через rebuild краще, ніж пониження версії на місці коли можливо).
  6. Уніфікуйте інструменти: XtraBackup для ребілдів, pt-heartbeat для лагу, pt-table-checksum для дрейфу і чіткий інцидентний runbook.
  7. Закріпіть нудні контрольні механізми: безпека читання, гігієна привілейованих акаунтів і регулярні drills з відновлення.

Чому Percona Server часто здається «більш стабільним» для реплікації

Це не магія; це важіль

Більшість нестабільності реплікації — це або (a) брак видимості, (b) операційна непослідовність, або (c) недостатній I/O. Percona Server зазвичай покращує (a) і (b) «з коробки», і добре поєднується з інструментами, які роблять (c) очевидним.

Команди операцій переходять, коли втомилися гадати

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

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

Одне цитатне нагадування для вашого монітора

Надія — це не стратегія. — парафразована думка, часто приписувана лідерам операцій та практикам надійності

Трактуйте це як нагадування: «реплікація зазвичай працює» — це надія. Тестована процедура відкату та ребілду — це стратегія.

FAQ

1) Чи Percona Server реплікує відмінно від MySQL?

Фундаментально — ні. Він використовує ті самі концепції реплікації: binlog-и, relay логи, applier-потоки, GTID (якщо увімкнено) і той самий протокол.
Практичні відмінності — в інструментації, фічах продуктивності та упаковці, орієнтованій на операційні потреби.

2) Чи перехід на Percona Server автоматично зменшить лаг реплікації?

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

3) Чи семісинхронна реплікація достатня, щоб запобігти втратам даних?

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

4) Коли варто використовувати statement-based чи row-based реплікацію?

Віддавайте перевагу ROW для коректності в більшості сучасних OLTP-систем. Statement-based може бути меншим за обсягом і іноді швидшим, але з ним легше отримати дрейф через недетермінованість.
Існує mixed mode, але податок на складність реальний.

5) Чому Seconds_Behind_Source іноді показує 0, хоча я відстаю?

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

6) Чи можна «пропустити» помилку реплікації, щоб знову запустити процес?

Можна. Але це як відрізати гальма, щоб зробити машину легшою. Пропуск помилок прийнятний лише з чітким розумінням кореня проблеми і планом відновлення консистентності
(checksum + цілеспрямований sync або rebuild). Інакше ви просуваєте пошкоджену оповідь.

7) Як зрозуміти, чи додавати більше паралельних воркерів реплікації?

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

8) Яка найкраща «нудна» практика для підвищення безпеки реплікації?

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

9) Якщо я вже використовую Orchestrator (або подібне), чи це знімає необхідність в деталях?

Ні. Orchestrator автоматизує процедуру; він не змінює реальність. Якщо репліки приймають записи або ваші метрики лагу неправильні, orchestrator швидко й впевнено провалиться.
Автоматизація підсилює і правильність, і помилки — обирайте, що ви їй даєте на вхід.

10) Коли не варто переходити на Percona Server?

Якщо ваша організація не в змозі підтримувати порядок пакетів, дисципліну версій або тестувати оновлення, перехід вам не допоможе.
Також, якщо ви на керованому хмарному сервісі, який не дозволяє Percona, зосередьтеся на практиках: інструментація, heartbeat, checksums, drills з відновлення і розмір I/O.

Наступні кроки, які можна зробити цього тижня

  1. Інструментуйте лаг правильно: розгорніть heartbeat і побудуйте графік. Припиніть покладатися на одне статусне поле як на істину.
  2. Аудит захисту від записів на репліках: переконайтесь, що super_read_only=ON скрізь і видаліть привілейовані облікові з batch job-ів.
  3. Запустіть checksum на одній критичній схемі: якщо виявите дрейф — розцінюйте це як провал процесу, а не як поодинокий баг.
  4. Зробіть контрольну перебудову репліки: заміряйте час, задокументуйте процес і виправте те, що вас здивувало.
  5. Визначте позицію надійності: задокументуйте налаштування і прийнятний вікно втрати. Якщо бізнес хоче «без втрат» — фінансуйте апаратне забезпечення і топологію.
  6. Якщо перехід на Percona розглядається: конвертуйте спочатку одну репліку, валідуйте, потім просувайте під планованою подією з fencing і планом відкату.

Стабільність реплікації рідко зводиться до одного параметра. Це питання того, чи ваша система швидко каже вам правду і чи команда відрепетирувала, що робити, коли вона цього не робить.
Якщо ви переходите з MySQL на Percona Server — робіть це заради цього: менше таємниць, більше відтворюваності і топологія, що поводиться так, як ви очікуєте.

← Попередня
ZFS snapdir=visible: Аудит снапшотів без істерик користувачів
Наступна →
Ubuntu 24.04: Secure Boot блокує драйвери — виправте без перевстановлення

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