8(800) 222 32 56
Панель управления
Решения для бизнеса

MySQL с GTID: простое аварийное переключение реплик без боли и сюрпризов

MySQL с GTID: простое аварийное переключение реплик без боли и сюрпризов
Подберите идеальное решение для ваших задач:
в России, США и Нидерландах обеспечат максимальную скорость. Воспользуйтесь всеми преимуществами надежного оборудования. Базовая помощь и техническое обслуживание входят в пакет услуг.

Оглавление

Введение

Когда мастер MySQL внезапно «умирает», главная задача DBA обычно не в том, чтобы восстановить железо, а в том, чтобы быстро и безопасно вернуть запись — не устроив двойного мастера и не потеряв больше данных, чем неизбежно при async‑репликации. GTID‑репликация сильно упрощает это упражнение: вместо плясок с master_log_file и master_log_pos вы опираетесь на факт «какие транзакции уже применены» и включаете авто‑позиционирование (MASTER_AUTO_POSITION=1). В результате переключение сводится к выбору самой актуальной реплики, её промоуту в мастер и переподключению остальных по GTID — с понятными проверками по gtid_executed/gtid_purged и статусам репликации. 

Статья написана в практичном формате (с командами и чек‑листами) и с редакционными требованиями к «живому» экспертному стилю. 

GTID простыми словами и чем он отличается от «позиционной» репликации

Традиционная асинхронная репликация MySQL ориентируется на бинарные логи: реплика читает события из binlog мастера, а при ручном переключении вам часто нужно знать имя файла binlog и позицию (координаты). MySQL прямо отмечает, что этот «традиционный» метод требует синхронизации файлов/позиций, тогда как подход на GTID не требует работы с лог‑файлами и позициями, заметно упрощая типовые операции администрирования и failover. 

GTID (Global Transaction Identifier) — это уникальный идентификатор транзакции (на практике — UUID источника + номер/диапазон), который позволяет однозначно сказать: «вот этот набор событий — это одна транзакция». MySQL использует GTID‑сеты (множества GTID), которые отражаются в переменных gtid_executed и gtid_purged

Два ключевых эффекта GTID для аварийного переключения:

  • Авто‑позиционирование (auto‑positioning): при MASTER_AUTO_POSITION=1 реплика в handshake отправляет мастеру GTID‑сет уже полученных/выполненных транзакций, а мастер отдает только недостающие. 
  • Идемпотентность применения: сервер автоматически пропускает транзакции с идентификаторами, которые он «уже видел». Это критично для корректного failover и безопасного переподключения реплик. 

Готовы перейти на современную серверную инфраструктуру?

В King Servers мы предлагаем серверы как на AMD EPYC, так и на Intel Xeon, с гибкими конфигурациями под любые задачи — от виртуализации и веб-хостинга до S3-хранилищ и кластеров хранения данных.

  • S3-совместимое хранилище для резервных копий
  • Панель управления, API, масштабируемость
  • Поддержку 24/7 и помощь в выборе конфигурации

Создайте аккаунт

Быстрая регистрация для доступа к инфраструктуре


Почему GTID обычно выигрывает в failover

  1. Проще выбрать кандидата на промоут: сравниваете @@GLOBAL.gtid_executed/Executed_Gtid_Set и понимаете, кто впереди. 
  2. Переподключение реплик без координатCHANGE MASTER TO ... MASTER_AUTO_POSITION=1 вместо подбора binlog‑координат. 
  3. Меньше ручных ошибок: меньше «человеческого фактора» на самых неприятных шагах. (Это не отменяет требований к дисциплине: fencing, read‑only, проверка на errant транзакции.)

Подготовка к аварийному переключению

Failover «в моменте» почти всегда выглядит красиво только у тех, кто подготовился заранее: настроил параметры, сделал наблюдаемость, решил вопрос «кто имеет право писать» и отрепетировал процедуру.

Ниже — минимальный практический набор.

Базовые требования GTID и репликационной цепочки

GTID должен быть включен на всех узлахgtid_mode=ON и enforce_gtid_consistency=ON. MySQL явно указывает эти параметры как базовые для GTID‑репликации. 

Для того чтобы реплика могла стать новым мастером (и чтобы другие реплики могли реплицироваться от неё), в топологии обычно требуется:

  • log_bin=ON (binlog включен) на репликах, которые потенциально станут мастером. MySQL в разделе про переключение источников отдельно отмечает, что реплики в такой группе обычно должны быть с включенным бинарным логированием. 
  • log_replica_updates=ON (или старое log_slave_updates) — тогда реплика пишет в свой binlog изменения, примененные SQL‑потоком репликации; это нужно для chain‑репликации и для промоута. 

Репликационные метаданные — в TABLE, а не в FILE (для crash‑safety):

  • В MySQL 5.7 это задается master_info_repository=TABLE и relay_log_info_repository=TABLE
  • В MySQL 8.0 таблицы‑репозитории — дефолт, а сами переменные считаются устаревающими (deprecated). 
    Смысл практический: метаданные применения транзакций коммитятся согласованно, поэтому прогресс репликации в таблицах остается консистентным даже при внезапной остановке. 

Формат бинлога и типичные «грабли»

Для большинства продакшн‑сценариев безопаснее ROW‑репликация (или MIXED там, где нужно), потому что statement‑репликация может страдать от недетерминированных выражений и особенностей логирования (особенно со stored routines/trigger‑логикой). MySQL прямо говорит, что ряд проблем statement‑репликации можно избежать переходом на row‑based. 
Дополнительно: изменение binlog_format считается deprecated (8.0.34) и в будущем ожидается, что останется только row‑формат. 

Read-only дисциплина: чтобы «случайные записи» не убили GTID

Практика простая: все реплики должны быть read‑only, а write‑трафик должен идти только на одного writer’а.

  • super_read_only=ON полезен как «страховка от людей с привилегиями»: в этом режиме клиенты не могут писать даже с расширенными правами; при этом репликационные потоки продолжают применять изменения. 
  • read_only и super_read_only — это именно локальные флаги: они не реплицируются, что удобно для отсутствия сюрпризов при изменении роли узла. 

Таймауты и наблюдаемость, чтобы не «проспать» фэйл

Для скорости детекта полезно понимать, как реплика решает «мастер пропал». MySQL описывает, что реконнекты запускаются, когда реплика достигает таймаута соединения (replica_net_timeout/slave_net_timeout) без данных/heartbeat. 

Что мониторить «ежедневно», а не только в день аварии:

  • статус потоков репликации (Slave_IO_Running/Slave_SQL_Running или их аналоги), лаги, ошибки. 
  • GTID‑наборы: @@GLOBAL.gtid_executed, а также в SHOW REPLICA STATUS поля Retrieved_Gtid_Set и Executed_Gtid_Set (по ним часто видно реальную картину лучше, чем по Seconds_Behind_Master). 

Отдельно о синтаксисе: начиная с MySQL 8.0.22 команды и статусы со словом SLAVE считаются deprecated (например, SHOW SLAVE STATUSSTOP SLAVE), вместо них используются SHOW REPLICA STATUSSTOP REPLICA и т. п. 

Таблица ключевых переменных и рекомендуемых значений

Переменная / опцияРекомендация для GTID failoverЗачем это нужноКомментарий по версии
gtid_modeONвключает GTID‑транзакцииобязательно для GTID‑репликации 
enforce_gtid_consistencyONзапрещает GTID‑небезопасные операциинужно выставить до включения GTID 
MASTER_AUTO_POSITION1 в CHANGE MASTER TOавто‑позиционирование по GTIDупрощает реконфигурацию/фэйл 
log_binONчтобы новый мастер имел binlog и историюMySQL рекомендует binlog на репликах в failover‑группе 
log_replica_updates / log_slave_updatesONчтобы реплика логировала примененные изменениятребуется для топологий, где реплика может стать источником 
master_info_repository / relay_log_info_repositoryTABLEcrash‑safe метаданные репликацииважно для 5.7; в 8.0 по умолчанию TABLE, переменные deprecated 
binlog_formatROWменьше недетерминизма и сюрпризовstatement‑проблемы решаются row‑форматом; ожидается future «row only» 
super_read_onlyON на репликахзащита от «случайных записей»блокирует клиентские записи даже при привилегиях; репликационные потоки продолжают применять 
skip_replica_start / --skip-replica-startвключить на репликахчтобы реплика не стартовала сама после рестартарекомендовано при GTID‑сетапе и в troubleshooting 
replica_net_timeout (slave_net_timeout)подобрать под SLA (обычно ниже дефолта)быстрее детектить пропажу источникавлияет на момент реконнекта/детекта 

Аварийное переключение: четыре сценария с командами и проверками

Перед командами — короткий принцип, который экономит часы жизни:

Failover = (fencing старого мастера) + (выбор лучшей реплики) + (промоут) + (переподключение остальных) + (проверка данных).

MySQL отдельно подчеркивает, что в failover‑ситуации переключение источника обычно «не ломает» структуру/целостность при условии, что все серверы исполняют одни и те же события, и вы аккуратно делаете переключение. 

Диаграмма процесса failover

flowchart TD
  A[Авария: master недоступен] --> B{Есть риск split-brain?}
  B -->|Да| C[Остановить запись: fencing/VIP/DNS/Firewall/Proxy]
  B -->|Нет| D[Переходим к выбору кандидата]
  C --> D
  D --> E[Собрать gtid_executed со всех реплик]
  E --> F{Есть один "самый впереди" без errant GTID?}
  F -->|Да| G[Промоут реплики в master]
  F -->|Нет| H[Разбор расхождений: лаг/errant/split-brain]
  G --> I[Переподключить реплики на новый master (AUTO_POSITION)]
  I --> J[Проверки репликации + консистентности данных]
  J --> K[Документировать инцидент, восстановить старый master как реплику]

Таблица сценариев и рекомендуемых действий

СценарийЦельРекомендуемый подходРиск данных
Мастер недоступен, реплики синхронизированыбыстро вернуть записьпромоут самой «здоровой» реплики, остальные переподключить по MASTER_AUTO_POSITION=1 минимальный для async‑репликации
Мастер недоступен, реплики расхожденывыбрать лучший источник правдыпромоут реплики с максимальным gtid_executed, выявление errant GTID через GTID_SUBTRACT, отстающих догнать, «сомнительные» — пересобрать/проверить средний/высокий
Split‑brain / двойной мастеростановить хаоснемедленный fencing, затем выбор авторитетного мастера и, как правило, пересборка второй стороны + верификация данныхвысокий
Возврат роли старому мастеру (failback)вернуться к исходной архитектуреподнять старый мастер как реплику нового (AUTO_POSITION), затем плановый switchover при «нулевом лаге»; при восстановлении из бэкапа корректно работать с gtid_purged контролируемый (при плановом окне)

Команды и ожидаемые выводы

ЗадачаКомандаОжидаемо в выводе
Проверить статус репликиSHOW SLAVE STATUS\G (<=8.0.21)  SHOW REPLICA STATUS\G (>=8.0.22)Slave_IO_Running/Replica_IO_Running, Slave_SQL_Running/Replica_SQL_Running, Executed_Gtid_Set, Retrieved_Gtid_Set 
Остановить репликациюSTOP SLAVE; / STOP REPLICA;потоки receiver/applier остановятся; receiver перестанет писать в relay log, applier — применять 
Остановить только IO или SQLSTOP REPLICA IO_THREAD; / STOP REPLICA SQL_THREAD;удобно «досушить» relay log или заморозить применение 
Переподключить к новому мастеру по GTIDCHANGE MASTER TO ... MASTER_AUTO_POSITION=1;реплика отправит GTID‑сет и получит только недостающее 
Сравнить GTID‑сетыSELECT GTID_SUBTRACT(setA,setB);увидите разницу (что есть в A и нет в B); аргументы — строки и должны быть в кавычках 

Сценарий: мастер недоступен, реплики синхронизированы

Ситуация: мастер не отвечает, но реплики были «в ноль» (или почти) и вы ожидаете, что у всех одинаковый Executed_Gtid_Set. Тут GTID дает максимально «скучный» промоут.

Шаги

Шаг первый — исключить split‑brain (fencing).
Если мастер «недоступен для вас», но доступен часть сети/приложений — это классическая ловушка. Практический fencing: отключить writer‑VIP, выключить маршрут, закрыть порт 3306 правилами firewall, остановить mysqld, отключить пул коннектов на приложениях (что у вас принято). Цель — гарантировать, что в старый мастер никто не пишет.

Шаг второй — выбрать кандидата.
На каждой реплике:

SHOW REPLICA STATUS\G
SELECT @@GLOBAL.gtid_executed\G

Ищем, чтобы Executed_Gtid_Set совпадал и не было ошибок. SHOW SLAVE STATUS в MySQL 8.0.22+ deprecated, но обычно работает как алиас. 

Пример ожидаемого фрагмента SHOW REPLICA STATUS\G:

Replica_IO_Running: No
Replica_SQL_Running: Yes
Seconds_Behind_Source: 0
Retrieved_Gtid_Set: 3E11FA47-71CA-11E1-9E33-C80AA9429562:1-84210
Executed_Gtid_Set:  3E11FA47-71CA-11E1-9E33-C80AA9429562:1-84210
Auto_Position: 1

Шаг третий — «досушить» relay log на кандидате (если нужно).
Если IO‑поток уже мертв из‑за недоступного мастера, но SQL‑поток еще применяет relay log, дайте ему закончить:

STOP REPLICA IO_THREAD;
-- ждём, пока SQL догонит
SHOW REPLICA STATUS\G

Остановка/старт потоков в MySQL описана явно: receiver читает и пишет в relay log, applier читает relay log и применяет. 

Шаг четвертый — остановить репликацию и промоутить кандидата в мастер.

На кандидате (реплике, которую делаем мастером):

STOP REPLICA;           -- или STOP SLAVE;
RESET REPLICA ALL;      -- или RESET SLAVE ALL; (удалит параметры подключения)
SET GLOBAL super_read_only = OFF;
SET GLOBAL read_only = OFF;
SHOW MASTER STATUS\G

RESET REPLICA — актуальное имя команды в MySQL 8.0.22+ (вместо RESET SLAVE). 

Важно: RESET MASTER на новом мастере в рамках failover обычно не нужен и опасен — он сбрасывает GTID‑историю выполнения и чистит mysql.gtid_executed

Шаг пятый — переподключить остальные реплики к новому мастеру.

На каждой оставшейся реплике:

STOP REPLICA;

CHANGE MASTER TO
  MASTER_HOST='new-master.example',
  MASTER_USER='repl',
  MASTER_PASSWORD='***',
  MASTER_PORT=3306,
  MASTER_AUTO_POSITION=1;

START REPLICA;

SHOW REPLICA STATUS\G

Смысл MASTER_AUTO_POSITION=1: реплика в handshake передает набор уже выполненных транзакций, а мастер отдает недостающие. 

Сценарий: мастер недоступен, реплики расхождены

Ситуация: кто‑то отстал, кто‑то догнал, а иногда у одной реплики есть «лишние» GTID (errant transactions). В этом сценарии важно не столько «быстро», сколько «правильно».

Развилка: отставание vs errant GTID

  1. Обычный лаг (replica просто отстала) — лечится выбором самой актуальной реплики и переподключением остальных (они догонят по GTID).
  2. Errant транзакции — транзакции, выполненные напрямую на реплике (в обход мастера). Percona описывает это именно так: errant transactions — это транзакции, которые существуют только на конкретной реплике, потому что были выполнены на ней. 

Практический алгоритм выбора кандидата

На каждой реплике снимите:

SELECT @@GLOBAL.gtid_executed AS gtid\G

Далее сравните наборы через GTID_SUBTRACT() — MySQL подчеркивает, что функции GTID работают со строковыми представлениями GTID‑сетов, поэтому аргументы должны быть в кавычках. 

Пример: сравнить реплику R2 с кандидатом R1:

-- Что есть у R2, чего нет у R1:
SELECT GTID_SUBTRACT('R2_GTID_SET', 'R1_GTID_SET')\G
  • Если результат пустой (или NULL/пустая строка) — R2 не «впереди» R1.
  • Если не пустой — R2 содержит транзакции, отсутствующие у кандидата: это либо потерянные транзакции мастера, либо errant, либо особенности multi‑source/фильтров.

Дополнение по фильтрам: в GTID‑репликации GTID «не фильтруются» так же, как данные; это сделано, чтобы GTID‑набор реплики оставался согласованным с источником и auto‑positioning не ломался. 

Если есть реплики «впереди» кандидата

Самый безопасный общий путь:

  • Промоутить реплику с максимальным и «чистым» gtid_executed (которая является супермножеством для остальных).
  • Реплики с «лишними» GTID (errant) — не делать их читателями «как ни в чем не бывало», пока не проверите данные.

Иногда пытаются «выровнять GTID» пустыми транзакциями (SET GTID_NEXT=...; BEGIN; COMMIT;). MySQL описывает эту технику (injecting empty transactions), но там же предупреждает о риске «залить» поток ложными транзакциями и необходимости чистки binlog’ов после таких манипуляций. 
Практический вывод: это инструмент для восстановления/провижининга и отдельных кейсов, а не универсальная «таблетка» от расхождений.

Сценарий: split-brain или двойной мастер

Ситуация: два узла принимали запись параллельно (часто из‑за сетевой сегментации или ошибочной логики VIP/Proxy). Это не «репликация сломалась», это «у вас две истории мира».

Честная реальность: автоматом красиво «склеить» два мастера нельзя без знания предметной области данных (конфликты уникальности, разные обновления одних строк и т. п.). Поэтому процедура в большинстве команд выглядит так:

  1. Немедленно остановить запись в оба узла, кроме одного выбранного «источника правды».
  2. Выбрать авторитетный мастер (обычно тот, к которому шел основной write‑трафик).
  3. Вторую сторону пересобрать (полная пересинхронизация) или выполнять очень аккуратную ручную консолидацию транзакций (если вы точно понимаете, что делаете).
  4. После стабилизации — проверка консистентности.

Инструменты типа Orchestrator полезны тем, что визуализируют топологию и умеют безопасно «перетаскивать» реплики между мастерами, отклоняя незаконные перестройки (например, там, где нарушаются правила репликации). 

Сценарий: восстановление старого мастера и возврат роли

Важный принцип: вернувшийся старый мастер нельзя просто включить обратно «как было». Его задача — сначала стать репликой нового мастера и догнать состояние.

Вариант: старый мастер вернулся с теми же данными (не переустанавливали)

  1. Сразу заблокируйте записи на старом мастере:
SET GLOBAL super_read_only = ON;

super_read_only запрещает клиентские обновления даже с привилегиями; при этом репликационные потоки продолжают применять. 

  1. Подключите его как реплику к текущему мастеру (теперь это «источник»):
STOP REPLICA;

CHANGE MASTER TO
  MASTER_HOST='current-master.example',
  MASTER_USER='repl',
  MASTER_PASSWORD='***',
  MASTER_AUTO_POSITION=1;

START REPLICA;
SHOW REPLICA STATUS\G
  1. Дождитесь нулевого лага и совпадения GTID‑наборов.

Вариант: старый мастер восстановлен из бэкапа/снапшота (GTID нужно выставить корректно)

Если вы восстанавливаете узел из снапшота и хотите «вклеить» его в GTID‑цепочку, MySQL описывает подход: можно выставить gtid_purged на реплике по значению gtid_executed с сервера, откуда брали бэкап — без необходимости «инжектить пустые транзакции». 

При этом помните ограничения:

  • RESET MASTER на GTID‑узле сбрасывает GTID‑историю выполнения (обнуляет gtid_purgedgtid_executed и чистит mysql.gtid_executed). 
  • В MySQL 5.6/5.7 изменить gtid_purged можно только когда gtid_executed пуст (для ряда операций). 
  • В MySQL 8.0 есть больше гибкости (в том числе можно выбирать режим «заменить» или «добавить» набор в gtid_purged). 

Типовой шаблон (осторожно, выполняйте только если понимаете последствия):

-- на восстановленном узле, до подключения к репликации
RESET MASTER;  -- только если нужно обнулить GTID-историю на "чистом" экземпляре
SET GLOBAL gtid_purged = 'UUID_OF_CLUSTER:1-84210';

CHANGE MASTER TO
  MASTER_HOST='current-master.example',
  MASTER_USER='repl',
  MASTER_PASSWORD='***',
  MASTER_AUTO_POSITION=1;

START REPLICA;

Проверка целостности данных и работа с relay log и «незавершенными» транзакциями

Что происходит с транзакциями «в полете»

  • Незакоммиченные транзакции мастера не попадают в binlog, а значит и не могут быть реплицированы; при аварии они либо откатываются, либо «не существовали» для репликации.
  • Relay log на реплике — это локальный буфер событий, полученных от мастера: receiver записывает, applier применяет. Остановка репликации останавливает оба: receiver перестает читать binlog источника и писать relay log, applier перестает читать relay log и выполнять. 
  • При многопоточной репликации (replica_parallel_workers > 0) MySQL закрывает «дырки» в последовательности при штатном STOP REPLICA, но предупреждает: если реплика остановлена неожиданно во время STOP REPLICA, последовательность примененных транзакций из relay log может стать неконсистентной. 

Практический вывод: в момент промоута лучше останавливать репликацию штатно и, если возможно, дать SQL‑потоку «досушить» relay log.

Проверка консистентности: pt-table-checksum и pt-table-sync

Для регулярной (и пост‑инцидентной) проверки очень полезен Percona Toolkit:

  • pt-table-checksum делает онлайн‑проверку консистентности репликации, выполняя checksum‑запросы на источнике; реплики, где данные отличаются, будут иметь другие результаты. 
  • pt-table-sync может синхронизировать различия, но он очень требователен к безопасной модели записи: инструмент прямо сообщает, что это небезопасно писать напрямую в реплики, и завершится с ошибкой, если обнаружит, что destination — реплика. 

Для failover‑практики это удобно так:

  1. после промоута — pt-table-checksum (по возможности на «новом мастере» как источнике правды);
  2. если есть расхождения — принять решение: чинить точечно pt-table-sync (очень аккуратно, чаще через источник), либо пересобрать проблемную реплику заново.

Best practices: как сделать failover «скучным»

Минимальный набор «чтобы не горело»

  1. Один writer, все остальные — super_read_only=ON, плюс процессный контроль (кто и как имеет право снять read‑only). 
  2. Всегда включайте авто‑позиционирование (MASTER_AUTO_POSITION=1) и проверяйте, что оно реально включено на всех репликах (бывают «ghosted GTID»‑ситуации, когда GTID есть, но auto‑position выключен — и тогда failover снова превращается в ручную боль). 
  3. Crash‑safe репликация: репозитории метаданных в TABLE (особенно если вы еще на 5.7). 
  4. Стабильный формат логирования (обычно ROW) и единая политика по binlog_format (избегайте неожиданных переключений формата на лету, особенно при наличии временных таблиц). 
  5. Тестируйте failover как учение, а не как сюрприз: симулируйте «мастер пропал», отрабатывайте fencing, промоут, переподключение, проверку данных.

Автоматизация: mysqlrpladmin/mysqlfailover, Orchestrator, MHA

Если вы хотите быстрее, чем «вручную по SSH»:

  • MySQL Utilities (mysqlrpladminmysqlfailover) исторически поддерживали промоут/фэйл при GTID: Percona в серии статей прямо пишет, что при GTID‑репликации эти утилиты можно использовать для promotion (manual и auto). 
    Но есть нюанс по жизненному циклу: Oracle отмечает, что MySQL Utilities покрыты Sustaining Support, а часть функций планировалась/планируется в MySQL Shell; репозиторий mysql/mysql-utilities на GitHub архивирован и read‑only. 
  • Orchestrator — сервис/инструмент управления репликационными топологиями: умеет discovery, визуализацию, понимает GTID и отбраковывает «нелегальные» перестройки.  (Плюс у Percona есть отдельный материал про работу с errant GTID через orchestrator.) 
  • MHA (Master High Availability Manager) — отдельный классический инструмент для автоматизации master failover и быстрого switchover; репозиторий менеджера описывает его именно как средство автоматизации failover и master switch. 

Практический совет для «среднего» уровня зрелости: начните с четкой ручной runbook‑процедуры + скриптов, а уже потом накрывайте это orchestrator/HA‑менеджерами.

Шаблон bash-скрипта для промоута и переподключения реплик

Ниже — скелет, который удобно адаптировать под вашу схему (VIP/ProxySQL/DNS). Он специально использует .my.cnf (или MYSQL_PWD) вместо пароля в командной строке.

#!/usr/bin/env bash
set -euo pipefail

# Usage:
#   ./gtid_failover.sh new_master_host replica1 replica2 replica3
#
# Preconditions:
# - fencing already done (old master cannot accept writes)
# - MySQL user has privileges to STOP/START REPLICA and CHANGE MASTER
#   (SYSTEM_VARIABLES_ADMIN/SUPER may be required to set globals) citeturn5search1

NEW_MASTER="${1:?new master host required}"
shift
REPLICAS=("$@")

MYSQL_OPTS=(--protocol=tcp --connect-timeout=3 --batch --skip-column-names)

mysqlq () {
  local host="$1"; shift
  mysql "${MYSQL_OPTS[@]}" -h "$host" "$@"
}

echo "[1/5] Promoting ${NEW_MASTER}..."

# Stop replication & make it writable
mysqlq "$NEW_MASTER" -e "STOP REPLICA; RESET REPLICA ALL;"
mysqlq "$NEW_MASTER" -e "SET GLOBAL super_read_only=OFF; SET GLOBAL read_only=OFF;"
mysqlq "$NEW_MASTER" -e "SHOW MASTER STATUS\G" || true

echo "[2/5] Repointing replicas to ${NEW_MASTER} using GTID auto-position..."

for r in "${REPLICAS[@]}"; do
  echo "  -> $r"
  mysqlq "$r" -e "STOP REPLICA;"
  mysqlq "$r" -e "
    CHANGE MASTER TO
      MASTER_HOST='${NEW_MASTER}',
      MASTER_PORT=3306,
      MASTER_USER='repl',
      MASTER_PASSWORD='***',
      MASTER_AUTO_POSITION=1;
  "
  mysqlq "$r" -e "START REPLICA;"
done

echo "[3/5] Checking replica status..."
for r in "${REPLICAS[@]}"; do
  echo "===== $r ====="
  mysqlq "$r" -e "SHOW REPLICA STATUS\G" | egrep -i 'Replica_(IO|SQL)_Running|Seconds_Behind|Executed_Gtid_Set|Retrieved_Gtid_Set|Last_(IO|SQL)_Error|Auto_Position' || true
done

echo "[4/5] Done. Now switch application writer endpoint (VIP/DNS/ProxySQL)."
echo "[5/5] Run pt-table-checksum for post-failover consistency check."  # citeturn0search3

Предупреждение: этот шаблон не решает split‑brain и не разбирает errant GTID — эти условия должны быть отсечены до запуска, иначе скрипт может сделать ситуацию хуже быстрее, чем вы успеете моргнуть.

Главные риски и как их снижать

Риск «номер один» — двойной мастер. Он почти всегда возникает не из‑за MySQL, а из‑за отсутствия fencing и контроля writer‑эндпойнта. Решение: жесткая процедура отключения старого мастера от записи + дисциплина super_read_only для всех остальных. 

Риск «номер два» — расхождение данных (silent drift) из‑за errant транзакций. Решение: мониторить GTID‑сеты, запретить записи на реплики, регулярно гонять pt-table-checksum

Риск «номер три» — ошибки при остановке/промоуте (особенно при параллельном applier): если реплика «убита» в момент STOP REPLICA, могут появиться несогласованности применения relay log. Решение: штатная остановка, контроль SQL‑потока, и crash‑safe метаданные в TABLE. 

Если GTID‑failover кажется «слишком простым», это хороший знак: он и должен быть простым — при условии, что вы заранее сделали его безопасным.

Как повысить антиплагиат: 8 эффективных способов 2021 года
Сайт

Как повысить антиплагиат: 8 эффективных способов 2021 года

Чем популярнее тема, тем сложнее написать уникальный текст. Большинство письменных трудов должно содержать цитаты, термины,

Медиасервер: зачем он вам нужен и как его настроить?
Решения для бизнеса

Медиасервер: зачем он вам нужен и как его настроить?

Медиасервер используется для хранения фильмов, музыки или личных фотографий. К нему можно подключиться по локальной сети из

ІоВ – одна из главных технологических тенденций 2021 года
DDoS

ІоВ – одна из главных технологических тенденций 2021 года

Устройства из категории IoT (Internet of Things, «интернет вещей») уже прочно вошли в нашу жизнь. Если