为什么写这篇:MySQL 实时同步有两条主流路径——应用层(Canal / Maxwell 解 binlog → 自定义消费者)和CDC 标准(Debezium → Kafka Connect → JDBC Sink)。前者灵活但要写代码,后者标准但坑点多。本文把两条路都走一遍,重点写真实环境的配置和报错。
适用读者:需要做 MySQL → MySQL/PG/ES 实时同步的中间件开发、DBA。
前置知识:了解 MySQL binlog、知道 Kafka 是什么、能用 docker 跑容器。
目录
- 同步方案对比:Canal vs Debezium vs Flink CDC
- Canal:基于 binlog 解析的轻量同步
- Debezium:CDC 标准的工业级实现
- JDBC Sink Connector:写入目标库
- 常见坑与排错
- 生产建议
1. 同步方案对比:Canal vs Debezium vs Flink CDC
| 维度 | Canal | Debezium | Flink CDC |
|---|---|---|---|
| 厂商 | Alibaba | Red Hat / Decodable | Apache |
| 协议 | 自定义 TCP / Kafka / RocketMQ | Kafka Connect(标准) | Flink SQL(标准) |
| 部署 | canal-server + canal-adapter | Connect + Source/Sink Connector | Flink Job |
| 转换能力 | adapter 内置 ES/HBase/MySQL | 需配 Sink,转换靠 SMT | SQL 表达 |
| 优点 | 文档全、中文社区、Java 友好 | 标准化、生态广 | 流式计算能力强 |
| 缺点 | 强耦合阿里系 | K8s 集成较新 | 重型,要 Flink 集群 |
| 适用 | 中小规模同步、阿里系架构 | 大规模、跨团队标准化 | 实时数仓 + 流计算 |
选型建议:
- 数据量 < 10 万 QPS,且目标库固定:选 Canal
- 跨团队、多源异构(MySQL + PG + Mongo + Oracle):选 Debezium
- 要做聚合、JOIN、流式 ETL:选 Flink CDC
2. Canal:基于 binlog 解析的轻量同步
2.1 架构
| |
2.2 Docker 部署
| |
2.3 MySQL 前置配置
| |
| |
2.4 canal-admin(Web 管理)
| |
Web 地址:http://internal.example.com:8089,默认账号 admin/123456。
2.5 canal-server 启动
| |
2.6 canal-adapter 启动
| |
坑点:canal-adapter 官方 JDK 镜像兼容性差,生产建议用自定义镜像(
lwd/jdk:8u371)。
3. Debezium:CDC 标准的工业级实现
3.1 三种部署方式
| 方式 | 适用 |
|---|---|
| Kafka Connect(推荐) | 生产环境,标准化、可观测性最好 |
| Debezium Server | 不想维护 Kafka 时,单独的应用 |
| Embedded Engine | 应用代码里嵌入 Debezium(自定义流) |
3.2 Kafka Connect 部署
| |
K8s 上可以参考 Strimzi 项目(包含 Kafka/Kafka Connect/Topic/User 三个 Operator)。
3.3 关键配置:调大消息体
默认 Kafka 消息体 1MB,大表 UPDATE/INSERT 必报:
| |
修法(kafka 端):
| |
坑点:直接在容器内改
server.properties不会生效,必须通过环境变量注入——这是无数人踩过的坑。
3.4 注册 Source Connector(监听 MySQL)
| |
snapshot.mode 4 种模式:
| 值 | 行为 | 适用 |
|---|---|---|
initial(默认) | 先全量快照,之后持续订阅 binlog | 首次接入 |
initial_only | 只做全量快照 | 一次性数据迁移 |
schema_only | 只同步 schema(不导数据),但持续订阅 DML | 已有数据,只关心后续变更 |
schema_only_recovery | 仅恢复 schema history topic(不导数据) | 灾难恢复 |
关键区别:
initial会把表所有数据先读一遍写入 topic;schema_only不读数据只读 schema history。DML 是 binlog 持续订阅,与 snapshot 无关。
3.5 常用管理 API
| |
4. JDBC Sink Connector:写入目标库
4.1 准备 Sink Connector JAR
Debezium Connect 自带 Source Connector(MySQL/PG/Mongo/Oracle/SQL Server/Db2),但 Sink Connector 需要自己注册:
| |
4.2 注册 Sink(同步多张表)
| |
4.3 关键参数解读
| 参数 | 含义 |
|---|---|
pk.mode=record_key | 用 topic key 作为目标表主键(必须有主键) |
insert.mode=upsert | 存在则更新、不存在则插入 |
auto.create=true | 目标表不存在时自动建(慎用,生产应提前建好) |
auto.evolve=true | 自动加字段(DDL 同步) |
delete.enabled=true | 同步 DELETE 事件 |
transforms.dropPrefix | 用正则去掉 topic 前缀,让表名干净 |
errors.tolerance=all | 出错进死信队列,不中断同步流 |
4.4 死信队列(DLQ)
启用 DLQ 后失败的记录会进指定 topic,方便排查:
| |
5. 常见坑与排错
5.1 RecordTooLargeException
| |
修法:见 3.3 调大消息体。
5.2 Failed to find any class that implements Connector and which name matches io.confluent.connect.jdbc.JdbcSinkConnector
没注册 Sink Connector JAR,按 4.1 操作。
5.3 No suitable driver found for jdbc:mysql://...
没把 MySQL JDBC 驱动 JAR 放到 connect 容器:
| |
5.4 Source Connector 卡在 RUNNING 但不消费
查看 task 状态:
| |
state=PENDING 多半是历史 topic 恢复中;RUNNING 但 Kafka offset 没变,可能是 binlog 已丢失——把 connector 删了重建并改 snapshot.mode=initial。
5.5 时间类型不匹配
Source 是 DATETIME(0) 但 Sink 写入失败。把 time.precision.mode 改成 connect 或在 SMT 里转字符串:
| |
5.6 Canal “table meta tsdb is out of sync”
canal-server 重启时找不回 binlog 位点。两种解法:
- 删
/home/admin/canal-server/conf/{instance}/meta.dat让它重做快照 - 在
instance.properties设canal.instance.tsdb.db.username/password把 tsdb 存进 MySQL
6. 生产建议
6.1 选型
- 单向同步(MySQL → MySQL):Canal adapter 最快
- 多源聚合:Debezium + JDBC Sink
- 强一致 + 转换:Flink CDC + Flink SQL
6.2 监控
| 指标 | 工具 |
|---|---|
| Canal lag | canal admin web 页面 |
| Debezium lag | JMX debezium.metrics + Prometheus + Grafana |
| Kafka consumer lag | kafka-consumer-groups.sh --describe |
| Sink 写入速率 | JDBC Sink task metrics |
6.3 反向思考:什么场景不能用?
| 场景 | 不建议 |
|---|---|
| 写入压力已经接近 MySQL 极限 | 同步会把 source 和 sink 同时打挂 |
| 频繁 DDL(加列改类型) | Debezium schema history 会越来越大 |
| 表没有主键 | 同步后 upsert 行为不可预期 |
| 大事务(> 1MB) | 需要先调大 max.request.size |
6.4 自建镜像
canal-adapter 官方镜像老旧、glibc 兼容性差。生产推荐自建镜像:
| |
| |
下一步
- MySQL 备份 + binlog 反解:见《MySQL 备份恢复实战》
- 多库适配(MySQL ↔ PG ↔ 国产):见《多数据库适配架构》
