canal

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);
    }
}

易错点与排错

相关命令

读完自测

  1. Canal 对 MySQL 的 binlog 格式和行镜像有什么要求?
  2. 为什么 Canal 消费需要幂等,位点丢失会怎样?
  3. DDL 变更为什么不能只依赖 Canal 自动同步?
答案
  1. 必须开启 binlog,使用 ROW 格式和 FULL 行镜像,否则拿不到完整的行前后值。
  2. 它按 at-least-once 投递,重启/位点回退/重试都会重复;位点丢失会重放或跳过数据。
  3. Canal 只解析并投递 DDL 事件,不会自动修改下游表结构,需要下游先执行或做 schema 管理。