6.5.10 Настройка репликации MySQL

MySQL-репликация это механизм, который автоматически синхронизирует данные между серверами в режиме реального времени. Она решает сразу три задачи: если основной сервер упадёт, данные не потеряются; нагрузку на чтение можно распределить между несколькими серверами; наконец, резервные копии можно снимать без остановки основной базы. В этом гайде рассматриваются два подхода к репликации. Первый — классический source-replica (он же master-slave): один главный сервер принимает все изменения, остальные их копируют. Второй — двусторонняя master-master репликация, где каждый сервер может одновременно и читать, и писать. Все примеры и команды актуальны для MySQL 8.0.23+, где Oracle переименовала устаревшие термины — там, где это важно, старый синтаксис отмечен отдельно.
Что нужно подготовить перед началом
Прежде чем трогать конфигурацию MySQL, убедитесь, что инфраструктура готова. Все последующие шаги предполагают, что у вас есть два отдельных сервера (физических, виртуальных или контейнера) с MySQL 8.0+ одинаковой версии.
Требования
- Два отдельных сервера — физических, виртуальных или контейнера
- MySQL 8.0+ одинаковой версии на обоих серверах
- Открытый порт 3306 открыт между серверами (проверьте:
telnet <ip_второго_сервера> 3306)
Какой тип репликации лучше выбрать
Source-Replica (master-slave) — лучший выбор для новичков и большинства production-сценариев. Подходит для масштабирования чтения (read replicas), создания резервных копий без нагрузки на production-сервер, аналитических запросов на отдельном сервере и простого failover (ручное повышение реплики до source). Сложность настройки низкая, риск потери данных минимальный при sync_binlog=1.
Master-Master (двусторонняя) — подходит только когда нужна запись на два узла в разных локациях или мгновенный failover без промоушна реплики. На практике большинство команд используют master-master в режиме active-passive: пишут только в один узел, второй держат как hot standby. Сложность высокая, риск конфликтов реальный при одновременной записи.
Group Replication / InnoDB Cluster — рекомендованный Oracle вариант для true multi-master. Имеет встроенный механизм разрешения конфликтов (certification-based), автоматический failover и quorum. Требует минимум 3 узла. Если нужен надёжный multi-master — это правильный выбор вместо ручного master-master.
Обратите внимание! В данной статье мы будем использовать следующие ip-адреса в качестве примера.
- source - 192.168.0.10
- slave - 192.168.0.20
Вам же нужно будет указать Ваши ip-адреса.

Source-Replica (master-slave) репликация
Это наиболее простой и распространённый тип репликации MySQL. Один сервер (source) принимает все операции записи, второй (replica) автоматически получает и применяет изменения. Реплика обычно работает как read-only узел и используется для разгрузки чтения, резервирования и повышения отказоустойчивости.
Если вы только начинаете работать с репликацией, лучше сразу использовать схему source-replica вместе с GTID (Global Transaction Identifier).
GTID — это уникальный идентификатор каждой транзакции в MySQL. Он позволяет реплике отслеживать не позицию в бинарном логе, а конкретные уже применённые транзакции.
Выглядит он примерно так:
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
Где:
3E11FA47-71CA-11E1-9E33-C80AA9429562— UUID сервера, на котором транзакция была создана;23— порядковый номер транзакции.
Почему лучше использовать GTID
Традиционный способ настройки репликации использует координаты бинарного лога:
SOURCE_LOG_FILESOURCE_LOG_POS
Это рабочий вариант, но он менее удобен:
- нужно вручную фиксировать файл и позицию;
- выше риск ошибки при первичной настройке;
- сложнее восстанавливать репликацию после сбоя;
- неудобнее выполнять переключение на другой source.
С GTID репликация становится проще и надёжнее:
- replica сама определяет, какие транзакции уже применены;
- не нужно вручную указывать
SOURCE_LOG_FILEиSOURCE_LOG_POS; - проще выполнять восстановление и переключение ролей;
- такой подход лучше подходит для автоматизации и масштабирования.
Конфигурация my.cnf на source-сервере
Файл: /etc/mysql/mysql.conf.d/mysqld.cnf (Ubuntu/Debian) или /etc/my.cnf (RHEL/CentOS).
[mysqld]
# Уникальный идентификатор сервера
server-id = 1
# Включение бинарного лога
log_bin = /var/log/mysql/mysql-bin.log
# Рекомендуемый формат бинлога
binlog_format = ROW
# Включение GTID
gtid_mode = ON
enforce_gtid_consistency = ON
# Разрешить подключения извне
bind-address = 0.0.0.0
# Безопасная запись бинлога на диск
sync_binlog = 1
# Срок хранения бинарных логов
binlog_expire_logs_seconds = 604800
# Максимальный размер файла бинлога
max_binlog_size = 100M
# (Опционально) Реплицировать только конкретные базы:
# binlog_do_db = mydb
# binlog_do_db = another_db
Конфигурация my.cnf на replica-сервере
[mysqld]
# Уникальный идентификатор сервера, отличный от source
server-id = 2
# Relay log для хранения событий от source
relay-log = /var/log/mysql/mysql-relay-bin.log
# Защита от случайных записей на реплике
read_only = ON
super_read_only = ON
# Бинарный лог на реплике
log_bin = /var/log/mysql/mysql-bin.log
# Записывать реплицированные события в бинлог реплики
log_replica_updates = ON
# Включение GTID
gtid_mode = ON
enforce_gtid_consistency = ON
После редактирования конфигурации на обоих серверах перезапустите MySQL:
sudo systemctl restart mysql
Настройка репликации с GTID
Шаг 1 — Создать пользователя для репликации на source
На source-сервере нужно создать отдельного пользователя, через которого replica будет подключаться и читать изменения из бинарного лога. Для этого пользователю выдаются права репликации. Рекомендуется ограничить доступ по IP-адресу replica-сервера, а не разрешать подключение с любого хоста.
-- Вариант A: caching_sha2_password (рекомендуется для MySQL 8.0)
CREATE USER 'repl_user'@'192.168.0.20' IDENTIFIED BY 'StrongP@ss123!';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'192.168.0.20';
FLUSH PRIVILEGES;
Альтернативно, если требуется совместимость со старой конфигурацией:
-- Вариант B: mysql_native_password
CREATE USER 'repl_user'@'192.168.0.20'
IDENTIFIED WITH mysql_native_password BY 'StrongP@ss123!';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'192.168.0.20';
FLUSH PRIVILEGES;
Если используется caching_sha2_password без SSL, на replica потребуется указать GET_SOURCE_PUBLIC_KEY=1 в команде CHANGE REPLICATION SOURCE TO.
Шаг 2 — Подготовить консистентный снимок базы на source
Перед созданием дампа нужно зафиксировать состояние данных, чтобы snapshot получился согласованным. Это особенно важно, если на source в этот момент продолжаются изменения. Блокировка позволяет избежать ситуации, когда часть данных попала в дамп до изменения, а часть — уже после него.
Для получения корректного дампа выполните:
FLUSH TABLES WITH READ LOCK;
Внимание! Не закрывайте эту сессию до завершения создания дампа. Если соединение оборвётся, блокировка снимется.
Шаг 3 — Сделать дамп базы
На этом этапе создаётся начальная копия данных, из которой replica получит текущее состояние базы. После импорта этого дампа replica сможет догонять source уже через репликацию бинарных логов. Для стартовой инициализации это базовый и наиболее понятный способ.
В отдельном терминале выполните:
mysqldump -u root -p \
--databases mydb \
--single-transaction \
--routines \
--triggers \
--events \
> /tmp/source_dump.sql
Пояснения:
--single-transactionдаёт консистентный снимок для InnoDB-таблиц;--routines,--triggers,--eventsвключают связанные объекты;- при использовании GTID нет необходимости опираться на
SOURCE_LOG_FILEиSOURCE_LOG_POSкак на основной механизм настройки.
После завершения дампа снимите блокировку:
UNLOCK TABLES;
Передайте дамп на replica:
scp /tmp/source_dump.sql user@192.168.0.20:/tmp/
Шаг 4 — Импортировать дамп на replica
Теперь нужно загрузить полученный дамп на replica, чтобы она стартовала не с пустой базы, а с актуальной копии данных source. После этого сервер replica будет готов принимать только недостающие транзакции через механизм GTID-репликации.
mysql -u root -p < /tmp/source_dump.sql
Затем подключитесь к MySQL на replica:
mysql -u root -p
Шаг 5 — Настроить репликацию через GTID на replica
На этом шаге replica получает параметры подключения к source и переводится в режим автоматического позиционирования через GTID. В отличие от старой схемы, здесь не нужно вручную указывать файл бинарного лога и позицию — MySQL сам определит, какие транзакции уже есть на replica, а какие ещё нужно получить.
Выполните:
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.0.10',
SOURCE_PORT=3306,
SOURCE_USER='repl_user',
SOURCE_PASSWORD='StrongP@ss123!',
SOURCE_AUTO_POSITION=1,
GET_SOURCE_PUBLIC_KEY=1;
Пояснения:
SOURCE_AUTO_POSITION=1включает репликацию через GTID;- в этом режиме MySQL автоматически определяет, какие транзакции уже применены на replica;
GET_SOURCE_PUBLIC_KEY=1нужен при использованииcaching_sha2_passwordбез SSL.
Шаг 6 — Запустить и проверить репликацию
После настройки соединения репликацию нужно запустить и сразу проверить её состояние. На этом этапе важно убедиться, что replica успешно подключилась к source, читает бинарный лог и применяет изменения без ошибок. Именно эта проверка показывает, что схема действительно работает, а не только формально настроена.
START REPLICA;
SHOW REPLICA STATUS\G
Ключевые поля для проверки:
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Seconds_Behind_Source: 0
Last_IO_Error:
Last_SQL_Error:
Что это означает:
Replica_IO_Running: Yes— replica подключилась к source и читает бинарный лог;Replica_SQL_Running: Yes— replica применяет полученные изменения;Seconds_Behind_Source: 0— отставание отсутствует;Last_IO_ErrorиLast_SQL_Errorдолжны быть пустыми.
Если оба потока работают и ошибок нет, репликация настроена корректно.

Двусторонняя (master-master) репликация
Двусторонняя репликация — это два сервера, каждый из которых одновременно является source и replica для другого. Изменения на Node1 реплицируются на Node2, и наоборот. Это существенно сложнее обычной source-replica, главная причина — риск конфликтов при одновременной записи на оба узла. MySQL не имеет встроенного механизма разрешения конфликтов для стандартной InnoDB-репликации.
Что меняется по сравнению с master-slave
Основных отличий пять. Во-первых, оба узла требуют включённый log_bin, поскольку каждый выступает source. Во-вторых, log_replica_updates должен быть ON на обоих узлах — без этого реплицированные события не попадают в локальный бинлог, и circular replication не работает. В-третьих, auto_increment_increment и auto_increment_offset необходимы для избежания коллизий первичных ключей. В-четвёртых, оба узла требуют пользователя для репликации. В-пятых, оба узла являются writable (не read-only).
Конфигурация my.cnf для двух узлов
Node 1 (IP: 192.168.1.10):
[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
relay_log = /var/log/mysql/mysql-relay-bin
log_replica_updates = ON
bind-address = 0.0.0.0
# Критично: разделение AUTO_INCREMENT между узлами
auto_increment_increment = 2
auto_increment_offset = 1
# Node 1 генерирует ID: 1, 3, 5, 7, 9...
binlog_expire_logs_seconds = 604800
max_binlog_size = 100M
Node 2 (IP: 192.168.1.20):
[mysqld]
server-id = 2
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
relay_log = /var/log/mysql/mysql-relay-bin
log_replica_updates = ON
bind-address = 0.0.0.0
# Node 2 генерирует ID: 2, 4, 6, 8, 10...
auto_increment_increment = 2
auto_increment_offset = 2
binlog_expire_logs_seconds = 604800
max_binlog_size = 100M
Ключевая переменная — auto_increment_increment=2 с разным auto_increment_offset на каждом узле. Это гарантирует, что Node 1 генерирует нечётные AUTO_INCREMENT-значения (1, 3, 5…), а Node 2 — чётные (2, 4, 6…), полностью избегая конфликтов первичных ключей. Для N узлов используйте auto_increment_increment=N с offset от 1 до N.
Переменная log_replica_updates (или log_slave_updates до MySQL 8.0.26) обеспечивает, что события, полученные от партнёра, записываются в собственный бинлог. Без неё circular replication невозможна — Node1 отправит изменение на Node2, Node2 применит, но не запишет в свой бинлог, поэтому Node1 никогда не «увидит» обратную репликацию. MySQL предотвращает бесконечные циклы благодаря server-id: каждый узел автоматически игнорирует события со своим собственным server-id.
Пошаговая настройка circular replication
После изменения конфигурации перезапустите MySQL на обоих узлах: sudo systemctl restart mysql.
Шаг 1 — Создать пользователей для репликации на обоих узлах:
На Node 1:
CREATE USER 'repl_user'@'192.168.1.20' IDENTIFIED BY 'StrongP@ss123!';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'192.168.1.20';
FLUSH PRIVILEGES;
На Node 2:
CREATE USER 'repl_user'@'192.168.1.10' IDENTIFIED BY 'StrongP@ss123!';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'192.168.1.10';
FLUSH PRIVILEGES;
Шаг 2 — Настроить Node2 как реплику Node1:
На Node 1 выполните SHOW MASTER STATUS; и запишите File/Position.
На Node 2:
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.1.10',
SOURCE_PORT=3306,
SOURCE_USER='repl_user',
SOURCE_PASSWORD='StrongP@ss123!',
SOURCE_LOG_FILE='mysql-bin.000001',
SOURCE_LOG_POS=<позиция_из_node1>,
GET_SOURCE_PUBLIC_KEY=1;
START REPLICA;
Шаг 3 — Настроить Node1 как реплику Node2:
На Node 2 выполните SHOW MASTER STATUS; и запишите File/Position.
На Node 1:
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.1.20',
SOURCE_PORT=3306,
SOURCE_USER='repl_user',
SOURCE_PASSWORD='StrongP@ss123!',
SOURCE_LOG_FILE='mysql-bin.000001',
SOURCE_LOG_POS=<позиция_из_node2>,
GET_SOURCE_PUBLIC_KEY=1;
START REPLICA;
Шаг 4 — Проверить репликацию на ОБОИХ узлах:
SHOW REPLICA STATUS\G
На каждом узле Replica_IO_Running и Replica_SQL_Running должны показывать Yes. Протестируйте: вставьте строку на Node1 (получит нечётный ID), затем на Node2 (получит чётный ID), убедитесь, что обе строки видны на обоих узлах.
Конфликты и как их избегать
MySQL не имеет встроенного разрешения конфликтов для стандартной InnoDB master-master репликации. Если оба узла одновременно изменят одну и ту же строку, репликация сломается с ошибкой 1062 (duplicate key) или 1032 (record not found). Наиболее безопасные стратегии для избежания конфликтов: направлять все записи только на один узел (второй как hot standby), разделять запись на уровне приложения (разные таблицы или диапазоны данных на разные узлы), или использовать UUID вместо AUTO_INCREMENT для первичных ключей.
Для полноценного multi-master с автоматическим разрешением конфликтов Oracle рекомендует MySQL Group Replication (доступна с MySQL 5.7.17, значительно улучшена в 8.0) или InnoDB Cluster, который объединяет Group Replication с MySQL Router и MySQL Shell для простого управления.
Распространённые ошибки
| Ошибка | Причина | Решение |
|---|---|---|
Replica_IO_Running: No |
Неверные учётные данные, firewall или неправильный bind-address |
Проверьте пользователя: SELECT user, host FROM mysql.user WHERE user='repl_user';. Убедитесь, что bind-address в my.cnf на source равен 0.0.0.0, а не 127.0.0.1. Проверьте подключение: telnet <source_ip> 3306 |
Authentication plugin 'caching_sha2_password' reported error |
Реплика не может получить ключ аутентификации без SSL | Добавьте GET_SOURCE_PUBLIC_KEY=1 в CHANGE REPLICATION SOURCE TO или переведите пользователя: ALTER USER 'repl_user'@'<replica_ip>' IDENTIFIED WITH mysql_native_password BY 'password'; |
Replica_SQL_Running: No — Error 1062 (Duplicate entry) |
Строка с таким ключом уже существует на реплике — кто-то вручную писал в реплику | Удалите конфликтную строку на реплике или пропустите ошибку через SET GLOBAL sql_slave_skip_counter = 1 |
Replica_SQL_Running: No — Error 1032 (Can’t find record) |
Событие пытается обновить или удалить строку, которой нет на реплике | Вставьте отсутствующую строку вручную или пропустите ошибку |
| Error 1236 (Binary log error) | Бинарные логи на source удалены раньше, чем реплика успела их прочитать | Только полная ресинхронизация: новый дамп с source и повторная настройка репликации с нуля |
Одинаковый server_uuid на обоих узлах |
VM или Docker-контейнер был склонирован вместе с auto.cnf |
Остановите MySQL, удалите /var/lib/mysql/auto.cnf, запустите MySQL — новый UUID сгенерируется автоматически |
Seconds_Behind_Source постоянно растёт |
Реплика не успевает применять изменения | Проверьте нагрузку на source, железо реплики и наличие крупных транзакций; реализуйте heartbeat-таблицу для точного мониторинга лага |
Заключение
Репликация MySQL 8.0 стала значительно удобнее благодаря обновлённой терминологии, GTID по умолчанию и бинарному логу, включённому «из коробки». Главное правило для новичков — начинайте с простой source-replica с GTID, всегда ставьте read_only=ON на реплике, используйте GET_SOURCE_PUBLIC_KEY=1 для caching_sha2_password, и держите binlog_expire_logs_seconds достаточно высоким, чтобы реплика успевала прочитать все логи. Master-master следует рассматривать только как active-passive failover, а для настоящего multi-master — переходить на Group Replication. И самое важное: если вы клонировали VM — всегда удаляйте /var/lib/mysql/auto.cnf перед запуском репликации.


