Debezium 与 Canal 深度详解
两者是目前国内 MySQL CDC 场景最主流的开源工具,本文从架构原理、核心组件、部署方式、消息格式、优劣势对比等维度做系统性介绍。
一、Debezium 深度解析
1.1 背景与定位
Debezium 由 Red Hat(现 IBM 旗下)开源,是基于 Apache Kafka Connect 的分布式 CDC 平台。它不直接推送消息,而是作为 Kafka Connect Source Connector 运行,将数据库变更事件写入 Kafka Topic,再由下游消费者处理。
- 开源协议:Apache 2.0
- GitHub:https://github.com/debezium/debezium
- 当前版本:3.x(基于 Kafka Connect 3.x)
- 支持的数据库:MySQL、PostgreSQL、MongoDB、SQL Server、Oracle、DB2、Cassandra
1.2 核心架构与组件
Debezium 并非独立运行的程序,而是运行在 Kafka Connect 框架上的 Connector 插件。
┌─────────────────────────────────────────────────────────────────┐
│ Kafka Connect 集群 │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Debezium MySQL Connector (Source Connector) │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │ │
│ │ │ Binlog Reader │ → │ Event Parser │ → │ Schema History│ │ │
│ │ │ (伪装从库) │ │ (解析binlog) │ │ (表结构变更) │ │ │
│ │ └──────────────┘ └──────────────┘ └───────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────────┐ │ │
│ │ │ Offset Mgr │ → Kafka Topic │ │
│ │ │ (binlog位置) │ (connect-offsets) │ │
│ │ └──────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────────┐
│ MySQL 主库 │ │ Kafka Topic │
│ (binlog) │ │ (数据变更事件) │
└─────────────┘ └────────┬────────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ ES Sink │ │ Data │ │ Flink │
│ Connector │ │ Warehouse │ │ Consumer │
└────────────┘ └────────────┘ └────────────┘
三大核心内部组件:
| 组件 | 职责 |
|---|---|
| Binlog Reader | 模拟 MySQL 从库,通过 MySQL Replication 协议订阅 binlog,读取 ROW 格式事件 |
| Event Parser | 将 binlog 二进制事件解析为结构化对象(表名、操作类型、变更前后数据) |
| Schema History | 记录所有表结构变更(DDL),确保历史 DDL 可追溯,用于重建索引结构 |
1.3 两种部署模式
模式一:Kafka Connect 分布式模式(生产推荐)
Connector 运行在 Kafka Connect Worker 集群中,由 Kafka Connect 统一管理 offset 存储、配置分发、故障恢复。
# 核心配置示例
name=inventory-mysql-connector
connector.class=io.debezium.connector.mysql.MySqlConnector
database.hostname=mysql-master
database.port=3306
database.user=debezium_user
database.password=xxx
database.server.id=85744
database.include.list=ecommerce
table.include.list=ecommerce.orders,ecommerce.products
topic.prefix=dbserver1 # Kafka Topic 前缀
snapshot.mode=initial # 首次启动做全量快照
schema.history.internal.kafka.bootstrap.servers=kafka:9092
schema.history.internal.kafka.topic=schema-changes # 存储表结构变更
Kafka Topic 命名规则:
{topic.prefix}.{database_name}.{table_name}
例:dbserver1.ecommerce.orders
模式二:Debezium Embedded(嵌入式,无需 Kafka)
Debezium 提供 debezium-embedded 模块,可以不依赖 Kafka Connect,直接在应用内嵌入运行:
DebeziumEngine<ChangeEvent<String, String>> engine = DebeziumEngine.create(Json.class)
.using((offset, source, visitor) -> {
// 每条变更事件在这里处理
ChangeEvent<String, String> event = new ChangeEvent<>(source, visitor);
processEvent(event);
})
.using(config().asProperties())
.build();
适用场景:轻量级同步、不想引入 Kafka 的团队、直接写入目标系统。
1.4 核心特性
① 一致性快照(Initial Snapshot)
当 Connector 首次启动时,如果 MySQL binlog 中没有足够历史(binlog 已过期),Debezium 会自动执行一次全量快照:
- 读取当前所有表的全部数据,写入 Kafka
- 记录当前 binlog position
- 切换到 binlog 实时增量同步
# 快照模式配置
snapshot.mode=initial # 仅首次启动做全量
snapshot.mode=schema_only # 只快照 schema,不含数据
snapshot.mode=configuration_based # 自行控制快照范围
snapshot.locking.mode=none # 快照时不锁表(MySQL 默认)
② Offset 持久化(断点续传)
Debezium 将 binlog position 存储在 Kafka Topic(connect-offsets)中:
key: {"server": "dbserver1"}
value: {"binlog_file": "mysql-bin.000123", "binlog_pos": 456, "ts_ms": 1735800000000}
Kafka 本身就是分布式存储,即使 Debezium 重启,也能从上次位置继续同步。
③ Schema Evolution(DDL 变更处理)
当源表执行 ALTER TABLE 时,Debezium 会:
- 将 DDL 语句写入
schema-changesTopic - 更新内部 Schema History
- 下游 Sink Connector 自动感知 schema 变更,动态更新目标表结构
④ 事件消息格式
{
"before": null,
"after": {"id": 1, "name": "手机", "price": 2999, "stock": 100},
"op": "c", // c=create/insert, u=update, d=delete, r=read(snapshot)
"ts_ms": 1735800000123,
"source": {
"version": "3.0.0",
"connector": "mysql",
"name": "dbserver1",
"ts_ms": 0,
"snapshot": "false",
"db": "ecommerce",
"sequence": "[1,2,3]",
"table": "products",
"serverId": 1,
"gtid": "uuid:1-99-123",
"file": "mysql-bin.000123",
"pos": 456,
"row": 0,
"thread": 42,
"query": null
}
}
1.5 优势与局限
| ✅ 优势 | ⚠️ 局限 |
|---|---|
| Kafka 生态完善,可对接所有 Kafka Sink | 依赖 Kafka,学习成本较高 |
| 支持 8 种数据库连接器 | 架构相对重量级 |
| Schema Evolution 原生支持 | 配置参数较多,调优复杂 |
| 社区活跃,文档最完善 | 单机性能不如 Canal(需 Kafka 中转) |
| Offset 存储在 Kafka,故障恢复强 | 运维组件多(ZK/Kafka/Connect) |
| 支持 Embedded 模式脱离 Kafka | - |
二、Canal 深度解析
2.1 背景与定位
Canal 由阿里巴巴内部开发,主要解决"双11"期间数据库变更实时同步到计算引擎的问题。2011 年开源,是国内最早、最广泛使用的 MySQL CDC 工具。
- 开源协议:Apache 2.0
- GitHub:https://github.com/alibaba/canal
- 语言:Java(适合 Java 技术栈团队)
- 对标:Debezium(但无需 Kafka,可独立运行)
2.2 核心架构与组件
Canal 采用 Server - Instance - Client 三层架构,一台 Server 可承载多个 Instance(每个 Instance 对应一个 MySQL 数据源):
┌─────────────────────────────────────────────────────────────────┐
│ Canal Server(JVM 进程) │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Canal Server(网络层:ServerSocket/NIO) │ │
│ │ ├── 接收 MySQL 主库的 binlog 协议 │ │
│ │ └── 管理多个 Instance 的生命周期 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Instance 1 │ │ Instance 2 │ │ Instance 3 │ │
│ │ (订单数据) │ │ (用户数据) │ │ (商品数据) │ │
│ │ ┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │ │
│ │ │ Parser │ │ │ │ Parser │ │ │ │ Parser │ │ │
│ │ │ Filter │ │ │ │ Filter │ │ │ │ Filter │ │ │
│ │ │ Sink │ │ │ │ Sink │ │ │ │ Sink │ │ │
│ │ └────────┘ │ │ └────────┘ │ │ └────────┘ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ MySQL 主库1 │ │ MySQL 主库2 │ │ MySQL 主库3 │
│ (binlog) │ │ (binlog) │ │ (binlog) │
└─────────────┘ └─────────────┘ └─────────────┘
Instance 内部数据处理流水线:
binlog 事件流
│
▼
┌──────────────────────────────────────────────────┐
│ 1. Parser(解析层) │
│ - 伪装 MySQL 从库,接收 binlog 二进制流 │
│ - 解析 binlog event(TableMap/RowData等) │
│ - 封装为 Entry(Canal 内部事件对象) │
└──────────────────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ 2. Filter(过滤层) │
│ - 按库名/表名/SQL类型 过滤事件 │
│ - 配置:canal.instance.filter.regex │
│ - 支持白名单/黑名单 │
└──────────────────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ 3. Sink(协调层) │
│ - 控制消费速度,避免下游过慢影响主从复制 │
│ - 按 batch(批次)向下游交付 │
└──────────────────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ 4. Store(存储层) │
│ - 内存 RingBuffer 或 metaq │
│ - 记录消费位点(position) │
└──────────────────────────────────────────────────┘
2.3 三种部署模式
模式一:TCP 直连消费(最简单)
Canal Server 直接通过 TCP 推送消息给 Client,适合轻量级同步:
MySQL → Canal Server → TCP → 自定义 Client → 目标系统(ES/Redis)
模式二:Kafka / RocketMQ 消费(推荐生产)
Canal 将消息投递到 Kafka,下游消费者按需消费:
MySQL → Canal Server → Kafka → 多个消费者(ES、Flink、存储)
模式三:Canal Adapter(官方适配器)
阿里巴巴提供开箱即用的适配器,支持直接写入:
| 适配器 | 说明 |
|---|---|
| ES Adapter | MySQL → Elasticsearch 同步,支持表→索引映射 |
| RDB Adapter | MySQL → MySQL/Oracle 等关系库同步 |
| HBase Adapter | MySQL → HBase 同步 |
| Kafka/RocketMQ | 通用消息队列适配器 |
2.4 核心配置参数
instance.properties 示例:
# 源数据库连接
canal.instance.guard=false
canal.instance.master.address=MySQL主库地址:3306
canal.instance.master.journal.name=mysql-bin.000001
canal.instance.master.position=4
canal.instance.master.timestamp=
canal.instance.username=canal_user
canal.instance.password=xxx
#binlog 过滤(正则表达式)
canal.instance.filter.regex=ecommerce\\.orders,ecommerce\\.products
canal.instance.filter.black.regex=
# DDL 处理
canal.instance.filter.druid.ddl=true # 是否解析 DDL
# 消费位点记录
canal.instance.positions.manually.mode=
MySQL 端必须创建的账号:
CREATE USER 'canal_user'@'%' IDENTIFIED BY 'xxx';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal_user';
FLUSH PRIVILEGES;
2.5 HA 高可用部署
Canal 支持 Server HA 和 Instance HA:
┌─────────────┐
│ ZK 集群 │
└──────┬──────┘
┌───────────┼───────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Canal │ │ Canal │ │ Canal │
│ Server 1 │ │ Server 2 │ │ Server 3 │
│ (主) │ │ (从) │ │ (从) │
└─────┬────┘ └─────┬────┘ └─────┬────┘
│ │ │
▼ │ │
┌──────────┐ │ │
│Instance A│ │ │
│(running) │← ─ ─ ─ ┘(竞争同一个Instance)
└──────────┘
ZooKeeper 负责选主,同一时间只有一个 Server 持有 Instance 的消费权,故障时自动切换。
2.6 优势与局限
| ✅ 优势 | ⚠️ 局限 |
|---|---|
| 无需 Kafka,单进程即可运行 | 不支持 PostgreSQL / MongoDB 等,只支持 MySQL |
| 阿里开源,国内社区大,资料多 | Schema Evolution 能力弱(DDL 需额外处理) |
| Canal Adapter 开箱即用(ES/RDB/HBase) | 高可用依赖 ZK,架构稍复杂 |
| Protocol Buffers 消息格式,体积小性能高 | 官方文档较旧,部分配置已过时 |
| 大量生产验证(阿里双11) | 社区活跃度下降(相比 Debezium) |
| 与 RocketMQ 同出一脉,适合阿里技术栈 | - |
三、Debezium vs Canal 深度对比
3.1 核心架构对比
| 维度 | Debezium | Canal |
|---|---|---|
| 运行框架 | Kafka Connect | 自有架构(不依赖 Kafka) |
| 消息队列 | 必须依赖 Kafka | 可选 Kafka / RocketMQ / TCP / 文件 |
| 多数据库支持 | ✅ 8 种数据库 | ❌ 仅 MySQL/MariaDB |
| 水平扩展 | Kafka Connect 集群天然支持 | 需额外部署多 Server 实例 |
| 消息格式 | JSON(带 schema)/ Avro | Protocol Buffers(轻量) |
| 消息体积 | 较大(包含完整 schema 元信息) | 较小(紧凑二进制) |
| Offset 存储 | Kafka Topic(connect-offsets) | ZK / local file |
| Schema History | Kafka Topic(自动管理) | 需手动处理 DDL |
3.2 功能特性对比
| 特性 | Debezium | Canal |
|---|---|---|
| Initial Snapshot | ✅ 自动完成 | ✅ 支持 |
| 断点续传 | ✅(依赖 Kafka offset) | ✅(依赖 ZK) |
| Schema Evolution | ✅ 原生支持 | ⚠️ 需 Adapter 或自行处理 |
| DDL 解析 | ✅ 完整解析 | ✅ 支持(但处理复杂) |
| 心跳事件 | ✅ 内置 Heartbeat | ⚠️ 需自行配置心跳表 |
| 过滤规则 | 表名/库名正则 | 库名/表名正则 |
| HA 高可用 | Kafka Connect 集群自带 | Canal Server + ZK |
| 监控指标 | JMX + Kafka Connect metrics | Prometheus + Canal metrics |
3.3 性能对比
| 维度 | Debezium | Canal |
|---|---|---|
| 吞吐能力 | 高(依赖 Kafka 分区并行) | 高(单实例即可达数十万 events/s) |
| 延迟 | 毫秒级(Kafka 写入延迟) | 毫秒级(可直接推送,减少一跳) |
| 资源占用 | 较高(Kafka Connect + JVM) | 较低(单一 JVM 进程) |
| 批处理能力 | Kafka Connect 批次控制 | RingBuffer 内存批次 |
3.4 运维复杂度对比
| 维度 | Debezium | Canal |
|---|---|---|
| 组件数量 | 多(ZK + Kafka + Connect + Debezium) | 少(Server + ZK 即可) |
| 学习曲线 | 陡峭(Kafka 生态) | 平缓(Java 技术栈友好) |
| 国内资料 | 较少(英文为主) | 丰富(阿里开源,社区活跃) |
| 升级维护 | Kafka 版本兼容性需关注 | 独立版本,升级简单 |
| 问题排查 | 链路长,定位复杂 | 链路短,定位容易 |
四、选型建议
场景一:已有 Kafka 生态
选 Debezium。Kafka Connect 天然是 Debezium 的运行环境,直接上手,无需引入新组件。Kafka 的 Topic 管理、分区、消费组机制与 Debezium 无缝配合。
场景二:仅同步 MySQL → Elasticsearch
选 Canal。Canal Adapter 原生支持 ES,直接配置 canal.instance.filter.regex 过滤需要的表,adapter.yml 映射索引字段,5 分钟可跑通。不需要引入 Kafka,运维成本最低。
场景三:多数据库 CDC(MySQL + PostgreSQL + MongoDB)
选 Debezium。一个平台覆盖所有数据源,Debezium 的 Connector 生态覆盖了主流数据库,统一管理。
场景四:微服务事件驱动(Database → Message → Multiple Services)
选 Debezium + Kafka。Kafka 的 Pub/Sub 模型天然适合一对多消费,一个表变更事件可以同时发给搜索服务、缓存服务、通知服务、日志服务。
场景五:不想引入 Kafka,团队是 Java 技术栈
选 Canal。Canal 本身是 Java 项目,与 Spring Boot 集成方便,可直接在 Java 应用中嵌入消费逻辑。
场景六:需要 Schema Evolution(DALTER TABLE 自动同步)
选 Debezium。Debezium 对 DDL 有完整的捕获和传播机制,配合 Kafka Schema Registry 可以做到自动 schema 演进。Canal 的 DDL 处理相对粗糙,需要较多手工介入。
五、典型配置示例
Debezium:MySQL → Kafka → Elasticsearch
# Kafka Connect connector 配置
{
"name": "mysql-to-es",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"database.hostname": "mysql-master",
"database.port": "3306",
"database.user": "debezium",
"database.password": "password",
"database.server.id": "85744",
"topic.prefix": "ecommerce",
"database.include.list": "ecommerce",
"table.include.list": "ecommerce.orders,ecommerce.products",
"snapshot.mode": "initial",
"schema.history.internal.kafka.bootstrap.servers": "kafka:9092",
"schema.history.internal.kafka.topic": "schema-changes"
}
}
Canal:MySQL → Kafka(不含 Kafka Connect)
# instance.properties
canal.instance.master.address=MySQL主库:3306
canal.instance.username=canal_user
canal.instance.password=canal_password
canal.instance.filter.regex=ecommerce\\.orders,ecommerce\\.products
canal.mq.topic=ecommerce-canal
canal.serverMode=kafka # 推送模式:kafka / rocketmq / tcp
# adapter.yml(ES 适配器配置)
es:
servers:
- host: elasticsearch:9200
indices:
- source: "ecommerce.products"
target: "products"
mapping:
id: id
name: name
price: price
stock: stock
本文档为 Debezium 与 Canal 的深度技术对比,如需进一步了解某个具体场景的配置方案或参数调优,请告知。