bigywater.tech
MySQL / InnoDB · 99

多源复制

真实给一个replica配上两个独立的复制channel,接入两个互不知晓的source,验证多源复制真实能不能把数据汇流到一起,以及路上会撞到什么坑。

2个channel并行
真实同一个replica同时接两个独立source
真实的账号冲突
两个source的同名CREATE USER真实互相打架

做的事:真实起第三个实例,给replica挂上第二个复制通道

代码-- 真实第三个独立实例,server-id=3 mysqld --server-id=3 --log-bin=source2-bin --gtid-mode=ON ... -- replica上,真实配一个独立命名的channel CHANGE REPLICATION SOURCE TO SOURCE_HOST='127.0.0.1', SOURCE_PORT=19312, ... FOR CHANNEL 'from-source2'; START REPLICA FOR CHANNEL 'from-source2';

验证:真实撞上了一个账号重名的坑

实测 · 本机performance_schema真实报出的错误
Worker 1 failed executing transaction '...':1 ...
Error 'Operation CREATE USER failed for 'repl'@'%' (User account already exists)'

第二个source上同样执行了CREATE USER 'repl'@'%'(为了给它自己的复制账号),这条DDL真实作为binlog事件的一部分被channel 2复制了过来——但repl这个账号早就已经因为channel 1的第一次复制真实存在于replica上了,两个channel的历史DDL真实在同一个实例上产生了冲突。这个坑真实印证了多源复制的一个现实约束:接入同一个replica的多个source,如果各自的历史操作里创建过同名对象(账号、数据库、表),真实有很大概率会在初次全量同步时撞车。

验证:跳过冲突的事务后,两个channel真实各自把数据送到了同一个replica

代码SET GTID_NEXT='...:1'; BEGIN; COMMIT; SET GTID_NEXT='AUTOMATIC'; -- 真实跳过冲突事务 START REPLICA FOR CHANNEL 'from-source2';
实测 · 本机执行输出
-- source1(19310)写入kiwi,source2(19312)写入SKU-200
SELECT 'channel 1' src, item, qty FROM shop.orders WHERE item='kiwi'
UNION ALL SELECT 'channel 2', sku, qty FROM inventory.stock WHERE sku='SKU-200';

src        item      qty
channel 1  kiwi      6
channel 2  SKU-200   75
两条真实来自完全不同、互不知晓对方存在的source的写入,真实同时出现在了同一个replica实例上,各自走自己的channel、各自维护自己的GTID集合、互不干扰。performance_schema.replication_connection_status里真实能按CHANNEL_NAME分别查看每个通道的状态。多源复制真实适合的场景是"汇总多个独立业务库的数据到一个分析实例",前提是各个source真实操作的是不重叠的库表,本文这次踩到的账号重名坑,也是设计多源复制拓扑时真实需要提前规划好的一个细节——通常建议每个source使用不同的复制账号名,而不是像本文这样图省事都叫repl。

分步演示:从账号冲突到双channel真实并行工作

每一步都是本文上面用真实三节点复制环境跑出来的原始结果。

两个独立source,真实汇流到同一个replica
这一步新验证的channel状态

    本文用到的工具

    • 本机真实的三节点复制实验环境(两个独立source + 一个双channel replica)
    • CHANGE REPLICATION SOURCE ... FOR CHANNEL + performance_schema.replication_connection_status
    京ICP备2026067502号-1京公网安备11010502063487号