server_id必须全局唯一且非0/1,replicate-same-server-id必须为OFF,优先使用replicate-wild-do-table而非binlog-do-db,GTID模式下需严格启用enforce-gtid-consistency,双主本质是写入路径收敛问题。

server_id 重复会导致复制流错乱
MySQL 双主架构里,server_id 不唯一是循环复制最直接的诱因。两个节点如果 server_id 相同,binlog 事件在对方眼里就“不认识自己是谁”,结果就是 A 发的事件被 B 执行后又原样发回给 A,A 再执行一次——死循环。
实操建议:
- 检查两台 MySQL 的
my.cnf,确认server_id是整数、全局唯一、且不为 0 或 1(某些旧版本对 1 有特殊处理) - 运行
SELECT @@server_id;实时验证,别只信配置文件——重启没生效、动态改过但没持久化都可能出问题 - 避免用 IP 或主机名做
server_id值(比如server_id = 192168101),易冲突;推荐用有意义的固定小整数,如101和102
replicate-same-server-id 必须关掉
这个参数默认是 OFF,但一旦被显式设为 ON,MySQL 就会忽略 server_id 检查,允许接收自己发出的事件——等于主动打开循环复制的大门。
常见错误现象:明明 server_id 不同,复制还是跑飞,SHOW SLAVE STATUS\G 里 Seconds_Behind_Master 忽大忽小,甚至出现主键冲突错误 ERROR 1062 (23000): Duplicate entry。
实操建议:
- 在所有从库(也就是双主中另一台的 slave 线程)配置中,确保没有
replicate-same-server-id = ON - 检查
mysqld --verbose --help输出,确认该参数当前值;或查SELECT @@global.replicate_same_server_id;,必须为0 - 改完记得
STOP SLAVE; START SLAVE;,否则参数不生效
binlog-do-db / binlog-ignore-db 不可靠,优先用 replicate-do-table
靠库级过滤来防循环(比如只记本机写入的库)看似合理,但实际极易失效:事务跨库、USE 语句缺失、存储过程隐式切换库都会绕过判断。
使用场景:你只想让双主之间同步 user_db,其他库本地写本地读,不参与复制。
实操建议:
- 弃用
binlog-do-db,它作用于 master 端,控制“记不记”,但双主中每台都是对方的 master,逻辑混乱 - 改用 slave 端的
replicate-do-table或replicate-wild-do-table,例如replicate-wild-do-table = user_db.% - 注意:这些规则对 DDL 无效,建表/删表仍会全量传播,如有需要得配合
replicate-ignore-db = mysql过滤系统库
GTID 模式下循环复制更隐蔽但危害更大
开启 gtid_mode = ON 后,MySQL 用 source_id:transaction_id 去重,理论上能自动拦截已执行过的事务。但双主中若未正确设置 enforce-gtid-consistency = ON,或存在非事务引擎表、CREATE TEMPORARY TABLE 等操作,GTID 就会漏判。
性能影响:GTID 自动去重本身开销不大,但一旦发生循环,事务反复重试、位点错乱、Retrieved_Gtid_Set 和 Executed_Gtid_Set 不一致,排查成本远高于传统模式。
实操建议:
- 双主 + GTID 必须配对启用:
gtid_mode = ON、enforce-gtid-consistency = ON、log_slave_updates = ON - 上线前用
mysqlbinlog --base64-output=DECODE-ROWS -v抽样检查 binlog,确认每个事务都有SET @@SESSION.GTID_NEXT - 不要依赖 GTID 自动防循环——它只是补救,不是设计替代品;
server_id唯一性和replicate-do-*规则仍是第一道防线
真正容易被忽略的是:双主不是高可用银弹,循环复制往往暴露的是业务写入路径没收敛——比如应用层同时连了两个主库,或者中间件路由规则没兜住。技术配置调对了,还得回头看看流量是不是真的只进一个口。










