Canal MySQL binlog 订阅与增量同步
canal 是阿里开源的 MySQL binlog 订阅工具,把自己伪装成从库,向 MySQL 发送 dump 协议请求,解析 ROW 格式 binlog 后投递给客户端或消息队列。核心组件是 canal-server(解析、位点、HA)和 canal-client(拉取、ack),1.1.x 还支持直接投递到 Kafka、RocketMQ、RabbitMQ、Pulsar。
它用于增量数据同步、缓存失效、宽表/搜索索引构建和异构迁移。与 Debezium 相比,Canal 更聚焦 MySQL、部署轻、对中文生态友好;Debezium 基于 Kafka Connect,连接器和 schema 演进能力更完整。与 DataX 这类批量同步相比,Canal 是持续订阅,延迟通常在秒级。
生产上必须使用 ROW 格式和 FULL 行镜像,规划唯一 server_id、位点持久化、DDL 处理和消费幂等。Canal 是 at-least-once,重启、位点回退或下游重试都会带来重复消息。
mysql -h 127.0.0.1 -P 3306 -uroot -p -e "SHOW VARIABLES LIKE 'log_bin'; SHOW VARIABLES LIKE 'binlog_format'; SHOW VARIABLES LIKE 'binlog_row_image';"
mysql -h 127.0.0.1 -P 3306 -uroot -p -e "SHOW MASTER STATUS;"
mysql -h 127.0.0.1 -P 3306 -uroot -p -e "CREATE USER 'canal'@'%' IDENTIFIED BY 'canal'; GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%'; FLUSH PRIVILEGES;"
sh bin/startup.sh
sh bin/stop.sh
tail -f logs/canal/canal.log
tail -f logs/example/example.log
MySQL 侧要求 log_bin=ON、binlog_format=ROW、binlog_row_image=FULL,并给 Canal 账号复制权限。conf/example/instance.properties:
canal.instance.master.address=127.0.0.1:3306
canal.instance.dbUsername=canal
canal.instance.dbPassword=canal
canal.instance.connectionCharset=UTF-8
canal.instance.filter.regex=app\\.order_.*
canal.instance.filter.black.regex=mysql\\.slave_.*
canal.instance.tsdb.enable=true
canal.mq.topic=app_order_binlog
filter.regex 在 properties 里要写成双反斜杠。conf/canal.properties 选择投递方式:
canal.port=11111
canal.serverMode=kafka
kafka.bootstrap.servers=127.0.0.1:9092
kafka.acks=all
canal.mq.flatMessage=true
# 或投递到 RocketMQ
canal.serverMode=rocketMQ
rocketmq.namesrvAddr=127.0.0.1:9876
客户端拉取与 ack:
CanalConnector connector = CanalConnectors.newSingleConnector(
new InetSocketAddress("127.0.0.1", 11111), "example", "", "");
connector.connect();
connector.subscribe("app\\..*");
connector.rollback();
while (running) {
Message message = connector.getWithoutAck(1000);
long batchId = message.getId();
if (batchId != -1) {
for (Entry entry : message.getEntries()) { handle(entry); }
connector.ack(batchId);
}
}
binlog_format=STATEMENT/MIXED 会导致拿不到行数据或解析异常;主库必须设为 ROW,切主后也要确认新主配置。binlog_row_image 不是 FULL 时,UPDATE/DELETE 缺少旧值,下游无法正确回放;要求 FULL。canal.instance.mysql.slaveId。REPLICATION SLAVE/REPLICATION CLIENT 会报 Access denied;授权后确认 host 匹配。caching_sha2_password 与旧驱动不兼容,可能认证失败;升级驱动,或短期改用兼容认证插件。conf/example/meta.dat,用 canal.instance.master.journal.name/position 或 GTID 显式指定起点。isDdl=true,但下游表结构不会自动变更;先在下游执行 DDL 再消费数据,或按版本开启/过滤 DDL。canal.serverMode 默认是 tcp(11111),改成 MQ 后客户端仍连 TCP 会一直等待;确认服务端模式与客户端协议一致。canal.mq.partitionHash,否则同一行的变更可能落到不同分区,顺序无法保证。canal.zkServers、destination 唯一性和实例日志。ROW 格式和 FULL 行镜像,否则拿不到完整的行前后值。