mysql官方不原生支持双主架构,需手动配置互为主从并严格规避冲突;必须设置auto_increment_increment/offset、禁用非安全语句、统一row格式、确保事务顺序;因脑裂与数据不一致风险高,生产环境多弃用而选用mha或group replication等方案。

跨公网做 MySQL 双主双向复制(即 master-master)风险极高,不建议在生产环境直接使用。公网延迟、丢包、连接中断会导致 auto-increment 冲突、GTID 执行错乱、数据覆盖甚至主从断裂不可逆。真正可行的方案是:用内网或 VPC 对等连接 + 隧道(如 WireGuard / SSH tunnel)模拟“逻辑内网”,再在此基础上配置双主。
为什么直接跨公网配双主会失败
MySQL 的双主依赖稳定、低延迟、有序的 binlog 传输。公网无法保证这三点:
- TCP 连接频繁断开 →
IO_THREAD停摆,Seconds_Behind_Master持续增长甚至变为NULL - 网络抖动导致 binlog event 乱序到达 →
GTID_EXECUTED不一致,START SLAVE报Could not execute Write_rows_v1 event on table - 两台机器同时写入同一张表的自增主键 →
Duplicate entry 'X' for key 'PRIMARY',且auto_increment_offset/auto_increment_increment在高并发下仍可能撞车 - 防火墙/NAT 设备重置连接或拦截 long-lived replication connection → 从库 silently stop,无人告警
必须做的前置网络层改造
不要试图在裸公网 IP 上直连 3306 做复制。先建立可控通道:
- 若两台云主机同属一个云厂商(如都在腾讯云),优先使用 VPC 对等连接 或 云企业网 CEN,打通内网路由,让它们像在同一局域网一样通信
- 若分属不同云厂商(如 AWS + 阿里云),用
wireguard在两台主机间建加密隧道,分配私有子网(如10.200.0.0/30),所有 MySQL 复制流量走该隧道接口 - 禁用所有中间设备(安全组、iptables、云防火墙)对隧道端口(如 UDP 51820)的限速或连接数限制
- 确认隧道两端能稳定
ping且traceroute跳数 ≤ 3,延迟,丢包率 = 0%
MySQL 配置关键项(双主必需)
两台机器配置完全对称,仅 server-id 和 auto-increment 参数错开:
-
server-id必须全局唯一:主机 A 设为101,主机 B 设为102 - 强制启用 GTID:
gtid_mode=ON+enforce_gtid_consistency=ON,禁用非事务引擎写入 - 避免自增冲突:
auto_increment_offset=1(A)/2(B),auto_increment_increment=2(两边相同) - 关闭
skip_slave_start,确保重启后自动拉起复制线程;但必须配合监控脚本检测Slave_IO_Running和Slave_SQL_Running - binlog 格式必须为
ROW,禁止混合模式;开启log_slave_updates(双主必需) - 禁用
replicate_ignore_db类规则——跨库写入时极易漏同步
示例片段(/etc/my.cnf):
[mysqld] server-id = 101 gtid_mode = ON enforce_gtid_consistency = ON log_bin = mysql-bin binlog_format = ROW log_slave_updates = ON auto_increment_offset = 1 auto_increment_increment = 2
复制用户与启动命令不能照抄文档
很多教程让你在 A 上执行 CHANGE MASTER TO MASTER_HOST='B公网IP'...,这是大忌。你实际应连的是隧道内网地址(如 10.200.0.2):
- 创建复制用户时,
HOST必须匹配隧道另一端的出口 IP,不是公网 IP:CREATE USER 'repl'@'10.200.0.2' IDENTIFIED WITH mysql_native_password BY 'xxx'; - 执行
CHANGE MASTER时,MASTER_HOST填隧道 IP,MASTER_PORT填 MySQL 实际监听端口(默认 3306),MASTER_AUTO_POSITION=1(GTID 必选) - 启动后立刻检查:
SHOW SLAVE STATUS\G,重点看Retrieved_Gtid_Set和Executed_Gtid_Set是否持续增长且差值稳定 - 严禁手动
STOP SLAVE; SET GLOBAL sql_slave_skip_counter=1; START SLAVE;—— GTID 模式下该命令无效,会报错
真正可用的跳过方式是:SET GTID_NEXT='xxx-xxx-xxx:12345'; BEGIN; COMMIT; SET GTID_NEXT='AUTOMATIC';,但仅限极小范围人工干预。
双主最脆弱的环节从来不是配置本身,而是网络层不可见的瞬断和数据库层缺乏实时校验。上线前务必用 pt-table-checksum 每日比对,且所有业务写入必须带明确的 DB_NAME.TABLE_NAME 前缀,避免跨库 DML 引发隐式同步失败。











