CDC 增量快照:大表同步与 Schema 变化处理

通过分块读取、水位线和 Schema 历史处理大表 CDC 同步,覆盖 PostgreSQL 与 MySQL 的差异、上线步骤和常见失败模式。

袋鼠云
袋鼠云
数据治理

大表做 CDC 同步时,优先采用“增量快照读取历史数据,同时继续读取日志变更”的方式,而不是长时间锁表或停掉实时流。具体做法是:为每张表选择稳定的主键或可排序键,把历史数据切成多个范围块;快照读取每个块时,用水位线记录已经覆盖的范围,并让同一时间产生的 INSERT、UPDATE、DELETE 继续从 binlog 或 WAL 进入变更流;下游再按事件顺序和主键语义合并。Schema 变化不能一概而论,必须先区分数据库、连接器版本和变化类型,尤其要把 PostgreSQL 与 MySQL 分开设计。

为什么大表要用增量快照

一次性初始快照的优点是逻辑简单:连接器建立一个一致的起点,读取表结构和当前数据,完成后再从日志位置继续消费。但表很大时,扫描时间会拉长,数据库读压力会集中出现;如果同步任务中断,重做成本也很高。更危险的是,历史读取和实时变更不是两个互不相关的任务:在扫描期间,业务仍可能修改同一行。没有协调机制,可能漏掉更新,也可能把旧的快照值覆盖到较新的变更值上。

增量快照把一个大任务拆成多个表级或范围级阶段。Debezium 文档描述的机制会先取得表的边界,再依据配置的块大小读取一段记录;执行过程中通过信号触发,并用水位线跟踪快照进度。块越小,单次查询和重试的代价越低,但查询次数、事件调度和元数据开销会增加;块越大,吞吐可能更高,却更容易造成数据库读峰值、长事务或单次失败重做范围过大。因此,块大小不是越大越好,应以源库可承受的读取并发、单块耗时和日志保留窗口共同决定。

先做四项设计检查

第一,确认分块键。优先使用唯一、稳定、可比较的主键。自增整数主键通常容易形成范围查询;复合主键、频繁更新的键或没有索引的业务字段会让范围划分变复杂。不要把会被更新的业务状态字段当作游标,否则行可能从一个范围移动到另一个范围,快照边界难以解释。

第二,确认日志窗口。增量快照不是绕过日志,而是要求快照期间的日志仍可被连接器读取。启动前记录 binlog 文件与位置,或 PostgreSQL 的 WAL/LSN 可用性;估算历史扫描耗时,再与日志保留周期比较。若扫描可能超过保留窗口,应该先降低块大小和源库压力,或先扩大保留周期,而不是直接启动。

第三,确认下游幂等。快照事件和变更事件可能以不同路径到达下游,重复是需要被设计处理的正常情况。以主键作为合并键,使用事件中的操作类型、源端位点或事件时间做版本判断;删除事件不能只靠“空值行”表达,要保留删除语义。若目标端只支持追加写入,就需要另建去重或最新状态层,不能把快照结果直接当作最终明细表。

第四,确认 Schema 历史。下面关于表名和 Schema 的规则只针对 Debezium 3.6 文档所述的 PostgreSQL connector 与 MySQL connector,不能泛化到其他 CDC 实现或其他版本。数据库当前 Schema 不等于每一条历史事件发生时的 Schema。对于 Debezium 3.6 MySQL connector,binlog 包含 DDL,连接器会据此维护表结构;连接器还会写内部 Schema history topic,用来按事件时间恢复结构。这个内部 topic 是连接器使用的历史,不应让普通消费应用直接依赖。若使用 MySQL Schema change topic 对外通知 DDL,还要保持内部历史 topic 的全局顺序,不能任意增加分区破坏顺序。

实时开发 StreamWorks

覆盖采集、开发、运维全链路的云原生一站式实时数据开发平台

了解产品

一套可执行的增量快照步骤

第一步,先只选择一张低风险表做演练,并保存当前行数、主键范围、最近更新时间分布和目标端计数。不要以“任务变成运行中”作为成功标准,成功必须包括历史行覆盖、期间变更可追、删除可见和重复可控。

第二步,通过连接器信号触发 incremental snapshot。对于 Debezium 3.6 的 PostgreSQL connector 和 MySQL connector,增量快照信号中的 data-collections 名称区分大小写,并且必须按对应连接器要求写成全限定名:PostgreSQL 使用 schema.table,MySQL 使用 database.table。下面的 public.orders 只适用于 PostgreSQL connector 示例;不要把这个命名规则外推到其他 CDC 实现或其他版本。实际信号载体可以是源库信号表或 Kafka signaling topic:

{
  "type": "execute-snapshot",
  "data": {
    "type": "incremental",
    "data-collections": ["public.orders"]
  }
}

第三步,观察每个块的读取进度、快照事件数量、实时变更数量和源库日志位点。一个合理的进度曲线应当持续前进;如果快照进度不动而变更位点持续增长,说明源库读取或下游处理已经形成瓶颈。不要只看总任务状态,因为它可能掩盖某一张热点表的长尾。

第四步,对同一主键同时出现的 READ、UPDATE 或 DELETE 做最终状态校验。假设快照先读到订单状态为“待支付”,随后日志产生“已支付”更新,目标端最终应为“已支付”。如果目标端先写入更新、后写入快照,就必须靠版本或位点规则拒绝旧值;如果目标端没有这种能力,就要把快照和实时流放入同一套可排序的合并逻辑。

第五步,完成后做分层核对:源端与目标端的主键集合、非空约束、删除数量、按时间或主键范围分布分别对比。全表行数相同不代表同步正确,新增一行和漏掉一行可能抵消;至少要抽样检查快照开始前、快照中间和快照结束后的变更。

在 StreamWorks 中,可以把 CDC 采集、任务运行指标、日志和告警放在同一条实时链路的运维视角下,但主键选择、Schema 兼容策略和目标端幂等仍需要按业务表逐项定义。

数据治理

统一标准、质量、安全与资产管理,沉淀高质量数据集,支撑经营决策、监管合规与 AI 应用。

了解解决方案

Debezium 3.6 PostgreSQL 与 MySQL connector 的 Schema 差异

以下结论只适用于 Debezium 3.6 文档中的两个具体 connector。Debezium 3.6 PostgreSQL connector 的增量快照有明确限制:官方文档指出,增量快照运行期间不支持 Schema 变化。如果在发送信号后、快照开始前发生 Schema 变化,文档还要求将 database.autosave 设为 conservative 以保证正确处理。因此,若要增加列、删除列、修改类型或变更主键,建议先暂停或错峰该 PostgreSQL connector 的增量快照,再执行 DDL,确认 Schema history 与下游契约完成更新后恢复。对于无法控制 DDL 窗口的系统,应把快照拆成更短的任务,并建立 DDL 变更门禁,而不是假设其他 CDC 实现也有相同限制。

Debezium 3.6 MySQL connector 的处理路径不同:只有在 incremental.snapshot.allow.schema.changes=true 时,连接器才会在增量快照期间检测 Schema 变化,并重新选择当前块以避免 DDL 锁定问题。即使启用该配置,主键变化仍不受支持,可能导致错误结果;列默认值的变化也可能要等到 DDL 从 binlog 被处理后才被检测到。因此,不能把 MySQL connector 的这一可选行为推广到 PostgreSQL connector 或其他 CDC 实现。实践上应把 DDL 分成三类:新增可空列通常是兼容变更;删除列、收窄类型会影响旧事件和下游解析;主键、表名和列类型重大变化应视为迁移事件,安排独立回放和校验。

在上述 Debezium 3.6 connector 范围内,Schema 变化的失败模式通常有三种。第一,下游 Avro、JSON Schema 或表结构校验拒绝新字段,表现为消费失败而不是源端失败;解决办法是先确认新增字段是否可选,并让消费者支持向后兼容。第二,连接器重启后找不到历史 Schema,原因可能是内部历史 topic 丢失、权限错误或被错误清理;这时不要直接切换到 recovery 模式,官方文档警告在最近存在 Schema 变化时这样做可能造成错误,应先确认最后一次停机前后的 DDL。第三,在 Debezium 3.6 MySQL connector 的增量快照期间修改主键,属于文档明确不支持的操作,可能导致范围边界与行定位不一致;这类情况应停止继续写入目标,重新设计快照或完整校准,而不是用重复消费掩盖差异。

什么时候不应使用增量快照

没有稳定主键、日志保留时间明显不足、下游无法幂等、Schema 变化无法协调时,增量快照会把不确定性放大。此时可以先做一次停机窗口内的阻塞快照,或者建立临时全量表再切换;代价是业务影响、额外存储和切换复杂度更高,但边界更清楚。

最后,把“可恢复”写进方案:记录快照信号、块进度、源端位点和目标端校验结果;失败后从未完成的范围重试,并允许重复事件经过幂等层。CDC 的目标不是让任何阶段都不出重复,而是让重复、顺序和 Schema 变化都有可解释、可验证的处理规则。

开启Data+AI 之旅

填写表单,获取专属解决方案

400-002-1024

工作日 9:00-18:00

关注公众号

获取最新产品动态与技术干货

关注公众号

企业微信

扫码添加企业微信