x

Debezium 与 Canal 深度详解

两者是目前国内 MySQL CDC 场景最主流的开源工具,本文从架构原理、核心组件、部署方式、消息格式、优劣势对比等维度做系统性介绍。


一、Debezium 深度解析

1.1 背景与定位

Debezium 由 Red Hat(现 IBM 旗下)开源,是基于 Apache Kafka Connect 的分布式 CDC 平台。它不直接推送消息,而是作为 Kafka Connect Source Connector 运行,将数据库变更事件写入 Kafka Topic,再由下游消费者处理。

  • 开源协议:Apache 2.0
  • GitHubhttps://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 会自动执行一次全量快照

  1. 读取当前所有表的全部数据,写入 Kafka
  2. 记录当前 binlog position
  3. 切换到 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 会:

  1. 将 DDL 语句写入 schema-changes Topic
  2. 更新内部 Schema History
  3. 下游 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
  • GitHubhttps://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 eventTableMap/RowData等      
     - 封装为 EntryCanal 内部事件对象)             
└──────────────────────────┬───────────────────────┘
                           
                           
┌──────────────────────────────────────────────────┐
  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 HAInstance 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 的深度技术对比,如需进一步了解某个具体场景的配置方案或参数调优,请告知。

Left-click: follow link, Right-click: select node, Scroll: zoom
x