canal 本身不负责迁移,只做增量订阅;必须自建消费端将 binlog 事件转为目标库可执行操作。它不连目标库、不生成 sql、不处理冲突/重试/幂等/schema 变更,因此无法单独完成同步迁移。

Canal 本身不负责“迁移”,只做增量订阅;想完成从 MySQL 到新库的实时同步迁移,必须自己搭消费端(比如用 Java 或 Python 写 client),把 canal-server 推出的 binlog 事件转成目标库可执行的写入操作。
为什么不能只靠 canal-server 就完成迁移
canal-server 的角色是伪装成 MySQL slave,拉取并解析 binlog,然后以自定义协议(TCP 或 Kafka)把 Entry(含 RowData、EventType 等)推给客户端。它不连目标库,也不生成 SQL,更不处理冲突、重试、幂等或 schema 变更。
- 常见错误现象:
canal-server启动成功、日志显示“connected to mysql”,但目标库数据没变化——这是误以为它自带同步能力 - 实际使用场景:你得写一个长期运行的
CanalConnector(Java)或SimpleCanalClient(Python),持续拉取、解析、转换、写入 - 性能影响:解析逻辑放在 client 端,若转换复杂(比如多表 join 后写 ES),容易成为瓶颈;建议把计算尽量下沉到目标库(如用 INSERT ... SELECT)或用 Flink 做流式 ETL
MySQL 配置和 Canal 启动的关键检查点
binlog 必须开启且格式为 ROW,否则 canal-server 拿不到行级变更。同时需创建专用账号并授权 SUPER 和 REPLICATION SLAVE 权限。
- 检查命令:
SHOW VARIABLES LIKE 'binlog_format';必须返回ROW;SHOW MASTER STATUS;确认有正在写的 binlog 文件 - 配置项
canal.instance.master.address要写 MySQL 实例真实 IP + 端口,不能写localhost(容器或跨主机时尤其容易错) - 兼容性注意:MySQL 8.0+ 默认认证插件是
caching_sha2_password,而老版本 Canal(v1.1.5 之前)不支持,需建用户时显式指定mysql_native_password
消费端写入新库时必须处理的三个现实问题
单纯把 INSERT/UPDATE/DELETE 事件原样写入目标库,在生产环境必然出错。
- 主键冲突:目标库已有数据,又收到重复
INSERT—— 解法不是忽略,而是先查后插(INSERT IGNORE)或用ON DUPLICATE KEY UPDATE,且要确保目标表有唯一索引 - 字段缺失或类型不匹配:源库加了新字段,client 未更新解析逻辑,会导致
SQLException: Column count doesn't match value count—— 建议用白名单方式明确声明需要同步的字段,而非* - 事务边界丢失:MySQL 的一个事务可能包含多条语句,
canal-server按 event 发送,client 收到的是离散事件。若目标库需要强一致性,得在 client 里缓存同一transactionId的所有事件,再批量提交
真正难的从来不是启动 canal-server,而是让消费端扛住长时间运行中的网络抖动、目标库临时不可用、DDL 变更、时钟漂移导致的顺序错乱——这些都得在 client 代码里做补偿,而不是指望配置调参解决。











