订阅更新

数仓增量同步怎么设计?

面试问 033 约 4 分钟读完 3 次阅读

本文目录
  1. 面试怎么回答
  2. 第一步:先确定“变化”从哪里来
  3. 第二步:把游标设计成可重复的边界
  4. 第三步:更新和删除都要有落地语义
  5. 第四步:让任务能够安全重跑和对账
  6. 一个典型场景

面试怎么回答

我会先根据源端能力选择更新时间、CDC 日志或快照比对。使用时间字段时,不只保存 last_time,而会用时间加主键形成稳定游标,并固定每批 High Watermark。目标端按业务主键幂等 Upsert,同时明确 Delete 的落地语义。游标只在写入成功后推进,失败可以安全重跑;每批记录新增、更新、删除和游标范围,并通过周期对账验证没有漏数。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

很多人会回答:

“记录上次同步时间,下次用 update_time > last_time 抽取就行。”

这个方案简单,但生产里很容易漏数。

同一秒内可能有多条更新,事务提交时间可能晚于业务时间,源表还可能发生物理删除。只保存一个时间点,并不能完整描述数据变化。

所以我理解的增量同步是:

先选择可靠的变化来源,再设计不会漏数的游标边界,同时处理更新、删除、重跑和对账。


第一步:先确定“变化”从哪里来

常见增量获取方式有三类。

1. 更新时间字段

通过 update_time 过滤新增和修改记录,改造成本低,适合源表有可靠更新时间的场景。

但它通常无法天然识别物理删除,还要确认更新时间是否由数据库统一维护,是否会被业务回写成旧值。

2. 日志型 CDC

从数据库 Binlog、WAL 等变更日志中获取 Insert、Update、Delete,并按日志位点继续消费。

它能更完整地还原变更,但要处理初始快照、日志保留、Schema 变化、断点恢复和重复事件。

3. 快照比对

定期把当前快照与上一次快照按业务主键比较,识别新增、修改和删除。

语义直观,但全量扫描和比对成本较高,更适合数据量可控、源端缺少可靠变更标识的场景。

三类增量捕获方式对比


第二步:把游标设计成可重复的边界

只保存一个 last_time 不够,至少要解决边界重复和边界遗漏。

一种常见做法是使用复合游标:

(update_time, primary_key)

查询条件可以表达为:

update_time > :last_time
OR (update_time = :last_time AND id > :last_id)

这样同一时间戳内的多条记录也能稳定排序。

批次开始时还应固定本次 High Watermark,而不是边读边追不断变化的“当前时间”。本批次只处理 (last_cursor, high_cursor],成功后再推进游标。

如果源端存在迟到提交,可以设置重叠回看窗口,但重叠会带来重复,目标端必须支持幂等 Upsert。


第三步:更新和删除都要有落地语义

增量同步不是“把新行追加进去”。

目标表首先要有稳定业务主键,才能把同一对象的多次变化合并到正确记录。

对于 Update,可以:

  • 覆盖当前状态表
  • 按版本写入历史表
  • 将变更事件追加到明细日志表

对于 Delete,也要提前确定:

  • 目标表物理删除
  • 写入 is_deleted=1 的软删除标记
  • 在历史层保留删除事件,在当前层移除记录

如果增量来源只有更新时间字段,通常还需要额外的删除清单、软删除字段或周期快照对账,否则源端删除后,数仓可能永远保留一条“幽灵记录”。


第四步:让任务能够安全重跑和对账

增量任务一定会遇到失败重跑。

如果同一个批次重跑两次就产生重复数据,说明同步链路没有真正完成闭环。

我通常会检查:

  • 批次游标是否在目标写入成功后再提交
  • 目标写入是否按业务主键幂等
  • 每批是否记录开始、结束游标和处理行数
  • 是否区分新增、更新、删除数量
  • 是否定期做源端与目标端的分区级、主键级对账

实时 CDC 也不能替代周期对账。日志断档、权限变化或下游异常都可能让链路悄悄偏离,只有对账才能验证最终状态。


一个典型场景

比如源表的 update_time 精度只有秒,上一批最后处理到 10:00:00,并把游标保存成这个时间。

同一秒内还有一条主键更大的记录,在上一批查询结束后才提交。下一批使用 update_time > '10:00:00',这条记录就被永久跳过。

表面上任务每天都成功,行数变化也不明显,但某个订单始终没有进入数仓。

修复方式不是简单改成 >=。使用 >= 会重复读取整个边界,还要依赖幂等去重。更稳妥的是复合游标、固定批次 High Watermark,再结合回看窗口与目标端 Upsert。

增量同步的核心不是“少读一些数据”,而是让变化可定位、可重放、可验证。


刷题进度保存在当前浏览器