能实现,但必须为每个主库显式指定 for channel,且所有主库 binlog_format 必须是 row,gtid 推荐开启;否则复制会静默失败或数据错乱。

能实现,但必须为每个主库显式指定 FOR CHANNEL,且所有主库 binlog_format 必须是 ROW,GTID 推荐开启——漏掉任一条件,复制会静默失败或数据错乱。
主库必须启用 ROW 格式 binlog
多源复制下,STATEMENT 或 MIXED 会导致非确定性语句(如 NOW()、UUID()、自增主键插入)在从库重放时结果不一致,最终数据分裂。MySQL 不会报错,但 SHOW REPLICA STATUS FOR CHANNEL 'xxx' 中的 Seconds_Behind_Master 会持续增长,或出现 Slave_SQL_Running_State: Waiting for dependent transaction to commit 等异常状态。
- 检查命令:
SHOW VARIABLES LIKE 'binlog_format';,输出必须是ROW - 修改方式(MySQL 8.0+):
SET PERSIST binlog_format = 'ROW';,然后重启 mysqld;5.7 可用SET GLOBAL,但重启后失效 - 注意:仅在从库上设
binlog_format = ROW没用,主库才是源头
每个 channel 名必须唯一且显式声明
不加 FOR CHANNEL 的 CHANGE REPLICATION SOURCE TO 默认使用空字符串 channel(''),第二次执行会直接报错:ERROR 3079 (HY000): Multiple channels exist, please specify channel name。这不是语法错误,而是 MySQL 强制要求你「命名并隔离」每条复制链路。
- 正确写法:
CHANGE REPLICATION SOURCE TO SOURCE_HOST='192.168.1.10', SOURCE_USER='repl_a', ... FOR CHANNEL 'master_a'; - channel 名建议带业务或环境标识,比如
'prod_order'、'log_analytics',避免后期混淆 - 启动也必须按 channel 启动:
START REPLICA FOR CHANNEL 'master_a';,START REPLICA;只会启动默认 channel(空字符串),其余仍处于Replica_IO_Running: No
GTID 开启后,MASTER_AUTO_POSITION = 1 是必需的
启用 GTID(gtid_mode=ON + enforce_gtid_consistency=ON)后,不能再用 SOURCE_LOG_FILE/SOURCE_LOG_POS 手动定位起点。否则会报错:ERROR 3077 (HY000): When @@GLOBAL.GTID_MODE = ON, all replication channels must use AUTO_POSITION。
- 配置时必须写:
CHANGE REPLICATION SOURCE TO ..., SOURCE_AUTO_POSITION = 1 FOR CHANNEL 'xxx'; - 主库需提前创建好 GTID-consistent 用户,并确保
Executed_Gtid_Set在从库上可被识别(可通过mysqldump --set-gtid-purged=ON导出时保留) - 若主库未开 GTID,就别强开——混合模式比全关更危险,容易卡在事务边界
表名冲突必须靠规则映射解决
两个主库都有 users 表,同步到同一从库会直接报错:ERROR 1050 (42S01): Table 'users' already exists,或者后续 DML 写入覆盖错库。MySQL 多源复制本身不提供自动重命名能力。
- 方案一(推荐):在从库上用
replicate_rewrite_db或replicate_rewrite_table(MySQL 8.0.23+)做映射,例如把主库 A 的app.users映射为app_a.users - 方案二:主库侧改造,统一前缀(如
order_users、log_users),从库无需额外配置 - 切记:不要在从库上手动建同名表再开复制——
sql_log_bin = 0临时关闭日志虽可绕过,但极易遗漏,导致后续 binlog 断点错位
最易被忽略的是 channel 名的「显式性」和表名冲突的「前置处理」:前者错一次就阻塞第二条链路配置,后者问题往往在上线后数小时甚至数天才暴露——因为初期只有 DDL 冲突报错,DML 冲突则直接静默覆盖数据。











