mysql多源复制不支持冲突检测与自动解决,因缺乏全局事务协调器和跨源写序一致性保障,导致同主键写入必报错;须通过分表、id偏移、复合唯一键或全局id等应用层隔离方案规避冲突。

MySQL 多源复制(Multi-Source Replication)本身不提供冲突检测或自动解决能力,一旦多个主库向同一个从库的同一张表写入相同主键或唯一键的数据,SQL_THREAD 会直接报错中断,比如 ERROR 1062 (23000): Duplicate entry 'xxx' for key 'PRIMARY'。这不是配置问题,是架构层面的硬限制。
为什么 MySQL 不处理多源写冲突
MySQL 的复制是基于 binlog event 的串行重放,没有全局事务协调器,也不维护跨源的写序一致性。它只保证单个主库的事件按顺序执行,对不同主库来的事件不做因果排序或冲突预检。这意味着:
-
relay_log中混入来自master_A和master_B的INSERT,若都插入id=100,从库执行到第二个时必然失败 - 即使你用
GTID,也无法跨源去重或跳过——gtid_executed是每个通道独立维护的 -
slave_skip_errors可临时跳过,但会掩盖数据不一致,且无法区分“真冲突”和“可安全跳过”的场景
必须在应用层或接入层做写隔离
最可靠的方式,是让不同数据源写入完全不重叠的记录空间。这比事后修复更可控、更可审计:
- 按业务域分表:例如
order_us来自美国主库,order_cn来自中国主库,共用一个从库但物理隔离 - 按主键/分区键加前缀或偏移:如美国主库写
id = 1000000 + origin_id,中国主库写id = 2000000 + origin_id,确保数值不交集 - 用复合唯一键替代单列主键:例如把
(region, order_id)设为唯一键,同时在应用写入时强制带上来源标识 - 禁用所有主库上的
AUTO_INCREMENT写法,改由中间件或应用生成全局唯一 ID(如 Snowflake、UUIDv7)
不得已要合并同构数据时,用外部工具做冲突裁决
如果业务强要求把多个同结构主库的数据汇聚到一张表(比如报表库),就不能依赖原生复制,得换路子:
- 停用多源复制,改用
mysqldump+pt-table-sync定期对账补漏(适合低频、离线场景) - 用
Debezium+Kafka+ 自定义消费者,收到变更后先查目标库是否存在冲突,再按策略决定 INSERT / UPDATE / SKIP / MERGE - 在目标表增加
source_id字段和updated_at字段,冲突时保留updated_at最大的那条(需业务能接受“最后写入胜出”) - 避免用
REPLACE INTO或INSERT ... ON DUPLICATE KEY UPDATE直接灌入从库——它们会掩盖主键冲突,但可能误删/覆盖本不该动的字段
真正麻烦的不是怎么跳过错误,而是怎么定义“这个冲突该以什么语义解决”。时间戳、业务优先级、数据可信度……这些逻辑没法塞进 slave_parallel_workers 里跑。越早把冲突判定下沉到写入端,后续链路就越轻量。











