MySQL 和 PostgreSQL 的 CDC 方案到底有什么区别?

喜欢把枯燥的技术文档变成"手把手教程",不讲空话,只讲怎么连、怎么写、怎么优化。


如果你在做实时数仓、跨库同步、或者数据中台,CDC 这个概念你一定绕不开。

Change Data Capture------变更数据捕获。简单说就是:源库的数据变了,你能实时知道变了什么,同步到目标端。

听起来简单,但方案选型时坑不少。定时轮询(ETL)延迟高、对源库压力大;日志解析方案性能好,但搭建复杂、运维门槛高。中间还有时间戳方案、触发器方案,各自有适用场景。

今天把 CDC 的主流方案拆开讲清楚,每种方案的原理、优缺点、搭建方式、踩过的坑。如果你正在选型或者正在搭 CDC 管道,这篇应该能帮你少踩几个坑。


CDC 是什么:为什么不用定时轮询

先解决一个基础问题:既然我要的是"源库变了,目标端同步",为什么不能定时查一下?

定时轮询(ETL)的逻辑是:每隔 N 分钟执行一次 SELECT * FROM table WHERE update_time > last_sync_time

问题有三个:

1. 延迟是固定的。 你设 5 分钟轮询,延迟至少 5 分钟。设 1 分钟,延迟至少 1 分钟。对于实时数仓或者实时风控,这个延迟受不了。

2. 对源库有压力。 每次轮询都是一次全表扫描或者范围查询。表大了之后,这条 SQL 本身就占资源。频率高了,跟业务查询抢资源。

3. 漏数据。 如果一条数据在两次轮询之间被插入又被删除,轮询就捕获不到。或者时间戳字段没更新,变更就漏了。

CDC 的思路不同:直接监听数据库的变更日志,变更发生的那一刻就知道。不是"定时去查",是"实时监听"。


CDC 的三种实现方式:时间戳、触发器、日志解析

先快速过一遍 CDC 的三种实现路径,再重点讲日志解析。

方式一:时间戳方案

每张表加 update_time 字段,定期扫描大于上次同步时间的记录。

优点 :实现最简单,不需要额外组件。

缺点 :就是上面说的那三个问题------延迟固定、有压力、漏数据。

适用场景:数据量小、延迟要求不高的离线同步。

方式二:触发器方案

在源库的每张表上建触发器,INSERT/UPDATE/DELETE 时把变更记录到一张中间表,CDC 程序读中间表。

优点 :能捕获所有变更,不漏数据。

缺点 :触发器是同步执行的,每次写入都要多写一条变更记录,源库写入性能直接受影响。表多了之后,触发器管理也麻烦。

适用场景:源库写入压力不大、需要精确捕获变更的小规模场景。

方式三:日志解析方案(重点)

直接解析数据库的事务日志------MySQL 的 binlog、PostgreSQL/KES 的 WAL------从中提取变更事件。

优点 :对源库几乎零侵入(只需要开启日志)、延迟低(毫秒到秒级)、不漏数据。

缺点 :搭建复杂度高,需要理解日志格式、处理乱序/重复、维护解析程序。

适用场景:实时数仓、跨库同步、数据中台------对延迟和数据完整性要求高的场景。

下面重点讲日志解析方案。


MySQL binlog 解析:Canal / Debezium / Maxwell

MySQL 生态里,binlog 解析是主流 CDC 方案。binlog 记录了数据库的所有变更事件,格式有 STATEMENT、ROW、MIXED 三种。做 CDC 必须用 ROW 格式,因为需要记录每条数据的具体变更内容。

Canal

阿里开源的 binlog 解析工具,国内用得最多。

arduino 复制代码
MySQL(开启 binlog ROW 格式)
    → Canal Server(伪装成 MySQL slave,拉取 binlog)
    → Canal Client(消费变更事件)
    → Kafka / 直写目标库

Canal 的核心思路是把自己伪装成一个 MySQL slave。MySQL 的 binlog 本来就是给 slave 同步用的,Canal 连上去,MySQL 就把它当 slave,把 binlog 推过来。Canal 解析后,通过 Client 消费。

优点 :国内生态成熟、社区活跃、中文文档多。支持 HA 部署。

缺点:只支持 MySQL。如果源库有 PostgreSQL,得换其他方案。

Debezium

Red Hat 开源的 CDC 平台,支持多种数据库。

markdown 复制代码
MySQL/PostgreSQL/KES(开启日志)
    → Debezium Connector(Kafka Connect 插件,解析日志)
    → Kafka(变更事件按 topic 分发)
    → Kafka Consumer(消费写入目标端)

Debezium 走的是 Kafka Connect 生态。每个数据库一个 Connector,Connector 解析日志后把变更事件发到 Kafka topic。消费者从 topic 取数据写到目标端。

优点 :多数据库支持(MySQL、PostgreSQL、SQL Server、Oracle 等)、和 Kafka 生态无缝集成、Schema 变更自动处理。

缺点:依赖 Kafka,架构复杂度上了一个台阶。

Maxwell

轻量级的 binlog 解析工具,输出 JSON 格式。

javascript 复制代码
MySQL(binlog ROW)
    → Maxwell(读取 binlog,输出 JSON 到 Kafka/Kinesis/文件)
    → 下游消费

优点 :部署简单、配置少、直接输出 JSON。

缺点:功能相对单一,不支持 HA,社区活跃度不如 Canal 和 Debezium。

对比总结

维度 Canal Debezium Maxwell
支持数据库 仅 MySQL MySQL/PG/SQL Server/Oracle 等 仅 MySQL
部署复杂度 中(需部署 Server + Client) 高(需 Kafka + Kafka Connect) 低(单进程)
HA 支持 支持 支持(依赖 Kafka) 不支持
Schema 变更 需手动处理 自动处理 需手动处理
社区活跃度 高(国内) 高(国际) 中低
适用场景 国内 MySQL 生态 多数据库 + Kafka 生态 轻量级快速接入

PostgreSQL WAL 解析:wal2json / pgoutput / Debezium

PostgreSQL 的 CDC 靠的是 WAL(Write-Ahead Log)逻辑解码。

WAL 是 PostgreSQL 的内部日志,记录所有数据变更。逻辑解码把 WAL 中的物理变更记录解析成逻辑变更(INSERT/UPDATE/DELETE 的行级数据)。

wal2json

PostgreSQL 的逻辑解码插件,把 WAL 解析成 JSON 格式输出。

ini 复制代码
PostgreSQL(开启 wal_level=logical)
    → wal2json 插件(逻辑解码,输出 JSON)
    → 消费程序(读取 JSON 变更事件)
    → 目标端

配置步骤

  1. 修改 postgresql.conf

    ini 复制代码
    wal_level = logical
    max_replication_slots = 4
    max_wal_senders = 4
  2. 重启数据库

  3. 创建 replication slot:

    arduino 复制代码
    SELECT pg_create_logical_replication_slot('my_cdc_slot', 'wal2json');
  4. 消费变更:

    sql 复制代码
    SELECT * FROM pg_logical_slot_get_changes('my_cdc_slot', NULL, NULL);

优点 :轻量、纯插件、输出格式清晰。

缺点:需要自己写消费程序处理 JSON、replication slot 如果消费不及时会导致 WAL 堆积。

pgoutput

PostgreSQL 10+ 内置的逻辑解码插件,不需要额外安装。

ini 复制代码
PostgreSQL 10+(wal_level=logical)
    → pgoutput(内置逻辑解码)
    → 消费程序(如 Debezium PG Connector)
    → Kafka / 目标端

优点 :内置、不需要额外安装插件、和 Debezium 集成好。

缺点:输出格式是 protobuf,需要 Debezium 等工具解析。

Debezium PostgreSQL Connector

和 MySQL Connector 类似,只是源端换成了 PostgreSQL/KES 的 WAL 解析。

ini 复制代码
PostgreSQL(wal_level=logical)
    → Debezium PG Connector(用 pgoutput 解析 WAL)
    → Kafka
    → 下游消费

和 MySQL Connector 类似,只是源端换成了 PostgreSQL 的 WAL 解析。配置和标准 PostgreSQL 完全一致,关键点是确保 wal_level=logical 和 replication slot 数量够用。Debezium 的 PG Connector 对 PostgreSQL 各个版本兼容性都很好。


CDC 管道搭建:完整链路

一个完整的 CDC 数据管道,链路是这样的:

markdown 复制代码
源数据库
    → 日志解析(Canal / Debezium / wal2json)
    → 消息中间件(Kafka / Pulsar,可选)
    → 数据转换(格式转换、字段映射、过滤)
    → 目标数据库(写入)
    → 监控告警(延迟、积压、错误率)

几个关键配置点

1. 源端日志配置

MySQL:binlog_format=ROWbinlog_row_image=FULL(记录完整的前后镜像)。

PostgreSQL:wal_level=logicalmax_replication_slotsmax_wal_senders 至少设为 4。

2. 复制槽管理

PostgreSQL/KES 的逻辑复制 slot 如果消费者断连,WAL 会持续堆积直到磁盘满。必须监控 slot 的 lag:

vbnet 复制代码
SELECT slot_name, active, 
       pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS lag_bytes
FROM pg_replication_slots;

如果 lag_bytes 持续增长,说明消费者断了,需要排查。

3. 乱序和重复处理

CDC 管道在异常情况下可能出现乱序或重复消费。目标端需要做幂等写入:

  • 用主键做 UPSERT(INSERT ... ON CONFLICT UPDATE
  • 或者在消息里带序列号,目标端按序列号去重

4. DDL 变更处理

表结构变更(加字段、改类型)是 CDC 管道最容易出问题的地方。binlog/WAL 里有 DDL 事件,但下游消费程序不一定能处理。

建议:DDL 变更时,暂停 CDC 管道、同步目标端 schema、再恢复管道。或者用 Debezium 的 Schema Registry 自动处理。


常见问题和排查

问题一:同步延迟越来越大

排查步骤:

  1. 看源端日志产生速度 :MySQL SHOW MASTER STATUS 看 binlog 位置变化,PostgreSQL pg_current_wal_lsn() 看 WAL 增长
  2. 看解析程序消费速度:解析程序的 lag 指标是否在增长
  3. 看目标端写入速度:目标库是否有写入瓶颈(锁等待、索引过多、磁盘 I/O 满)
  4. 看消息中间件积压:Kafka topic 的 consumer lag

问题二:数据不一致

排查步骤:

  1. 抽取关键表抽样比对:源端和目标端按主键对比几条数据
  2. 检查 replication slot 是否有跳过pg_replication_slots 的 active 状态
  3. 检查是否有 DDL 变更没同步:源端加了字段,目标端没加,写入会报错
  4. 检查幂等写入逻辑:是否有重复消费导致数据翻倍

问题三:源库性能受影响

CDC 对源库的影响主要在日志写入。binlog/WAL 开启后,每次写入多一步日志记录。

优化

  • binlog/WAL 放独立磁盘,不和业务数据盘争 I/O
  • 适当调整日志文件大小和轮转策略
  • 过滤不需要同步的表(临时表、日志表)

方案选型决策框架

你的场景 推荐方案 理由
源库只有 MySQL,团队熟悉国内生态 Canal + Kafka 成熟、文档多、中文社区支持好
源库有多种数据库(MySQL + PG + Oracle) Debezium + Kafka 统一平台、多源支持
源库是 PostgreSQL,想要轻量方案 wal2json + 自写消费程序 配置简单、无额外依赖
源库是 PostgreSQL,需要和 Kafka 集成 Debezium PG Connector 开箱即用,和 Kafka 生态无缝集成
数据量小、延迟要求不高 时间戳轮询 最简单、零额外组件
需要秒级延迟、高可靠性 日志解析 + Kafka + 幂等写入 工业级方案,生产验证充分

CDC 管道上线前检查清单

  • 源库日志格式正确(MySQL ROW / KES logical)
  • replication slot 数量足够
  • WAL/binlog 磁盘空间监控已配置
  • 目标端幂等写入逻辑已实现
  • DDL 变更处理流程已确认
  • 不需要同步的表已过滤
  • 延迟监控告警已配置(超过 1 分钟告警)
  • 数据一致性抽样验证已跑过
  • 故障恢复流程已测试(消费断连、重启、追赶)
  • 源库性能基线已采集(开启 CDC 前后的对比)

总结

CDC 不是"选个工具装上就行"的事。

日志解析是核心方案,但选 Canal、Debezium 还是 wal2json,取决于你的源库类型、团队技术栈、架构复杂度接受度。MySQL 生态选 Canal 最省心,多数据库混选 Debezium,PostgreSQL/KES 轻量场景用 wal2json 就够了。

管道搭建之后,重点监控三件事:复制槽 lag(防 WAL 堆积)、消费延迟(防数据滞后)、数据一致性(防丢数据)。DDL 变更是最大隐患,必须有处理流程。

CDC 是实时数据链路的基础设施。地基打好了,上面的实时数仓、数据中台、跨库同步才能稳。

后续我会继续分享数据库版本升级实战、云数据库 vs 自建这些话题,跟着我一篇篇学,数据库这块就没问题了。

有问题评论区见。


喜欢把枯燥的技术文档变成"手把手教程"。关注我,数据库这块我们一起搞定。

相关推荐
SelectDB1 小时前
灵犀科技统一数据服务平台:基于 Apache Doris / SelectDB 实现存储降本 60%、计算提效 10 倍
数据库
让学习成为一种生活方式1 小时前
KMC 3.2.4 安装与使用--生信工具108
数据库
今天AI了吗1 小时前
从聊天到委派:AI Agent 如何推进长期任务
数据库·人工智能·python·sql·rust
两万五千个小时2 小时前
DeepSeek Harness 从 0 开始:08 Compaction 模块(上下文压缩)
人工智能·程序员·架构
得物技术2 小时前
EP-Harness:从个人 AI Coding 到团队级 Agent 工作流|得物技术
后端·程序员·架构
heimeiyingwang2 小时前
【架构实战】可观测性三支柱实战:Metrics、Logging、Tracing 如何统一落地
开发语言·架构·php
Jucai_in_AI2 小时前
企业培训场景下的个性化课程推荐系统设计与实现:混合推荐架构的工程实践
架构
—Miss. Z—2 小时前
第11章 故障管理
网络·数据库·oracle