双主互为主从必须启用GTID模式(gtid_mode=ON且enforce_gtid_consistency=true)、binlog_format=ROW、错开auto_increment_offset/ increment,并用MASTER_AUTO_POSITION=1配置复制;Keepalived需用脚本检查复制状态而非仅端口。

双主互为主从必须启用 GTID 模式
不启用 gtid_mode=ON 的双主配置,上线后大概率在写入高峰或网络抖动时出现同步断裂、事务重复或空洞,且无法安全 failover。GTID 是唯一能保证事务全局唯一、可追溯、避免手动定位 binlog 位置出错的机制。
必须同时开启两个参数:gtid_mode=ON 和 enforce_gtid_consistency=true。MySQL 启动时会校验二者是否共存,缺一即拒绝加载。若只开前者而漏后者,后续执行 CREATE TEMPORARY TABLE 或非确定性函数(如 NOW())会直接报错中断复制。
binlog_format 必须设为 ROW —— STATEMENT 或 MIXED 在双写场景下可能因主库执行顺序与从库重放顺序不一致,导致数据错乱。例如:同一时间两台主库并发更新同一条记录,STATEMENT 格式下无法保证重放结果一致。
自增主键冲突是双主最常踩的坑
MySQL 默认 auto_increment_increment=1、auto_increment_offset=1,两台主库同时插入新行,必然生成相同 ID,触发 ERROR 1062 (23000): Duplicate entry 'X' for key 'PRIMARY'。
必须错开两台机器的自增序列:
- master1 配置:
auto_increment_increment = 2,auto_increment_offset = 1→ 生成 1, 3, 5, … - master2 配置:
auto_increment_increment = 2,auto_increment_offset = 2→ 生成 2, 4, 6, …
该配置需写入 /etc/my.cnf 的 [mysqld] 段,并重启 mysqld 生效。已运行的库若未提前配置,不能在线修改;必须停写、用 ALTER TABLE tbl AUTO_INCREMENT = N 手动对齐起始值后再启用。
CHANGE MASTER TO 必须用 MASTER_AUTO_POSITION=1
GTID 模式下,MASTER_LOG_FILE 和 MASTER_LOG_POS 被完全忽略。若误填,SQL 线程会卡死在 Waiting for gtid set to be executed 或报 Could not find the first log file name in binary log index file。
正确命令格式为:
CHANGE MASTER TO MASTER_HOST='192.168.4.52', MASTER_USER='repluser', MASTER_PASSWORD='Abc-1234', MASTER_AUTO_POSITION=1;
执行前确保双方已创建复制用户,并授予 REPLICATION SLAVE 权限。注意:两台机器都要执行 CHANGE MASTER TO,彼此指向对方 —— 这才是“互为主从”。
启动后立刻检查:SHOW SLAVE STATUS\G 中 Slave_IO_Running 和 Slave_SQL_Running 均为 Yes,且 Retrieved_Gtid_Set 与 Executed_Gtid_Set 应持续增长并保持包含关系。
Keepalived 不能只靠端口检测来判断 MySQL 健康
默认的 TCP_CHECK 只连 3306 端口,MySQL 进程活着但复制早已卡死时,VIP 仍会漂过去,导致业务读到延迟数分钟的数据,甚至写入失败。
必须用自定义脚本做真实健康判定,脚本核心逻辑应包含:
- 检查
Slave_IO_Running = Yes且Slave_SQL_Running = Yes - 检查
Seconds_Behind_Master (按业务容忍度调整) - 返回非 0 值表示异常,触发
notify_down
vrrp_script 块中必须调用该脚本,并在 vrrp_instance 中引用;同时设置 nopreempt yes,避免主库恢复后抢回 VIP 引发脑裂。这点极易被忽略,一旦发生,两台主库会同时接受写入,彻底破坏数据一致性。











