写点什么

3 分钟搞懂 Apache SeaTunnel CDC 数据同步

作者:白鲸开源
  • 2025-06-17
    天津
  • 本文字数:3083 字

    阅读完需:约 10 分钟

3分钟搞懂 Apache SeaTunnel CDC 数据同步

CDC 简介

CDC(Change Data Capture)是一种用于跟踪数据库库变更事件(插入、更新、删除)中的行级更改,并将事件以发生的顺序通知到其他系统处理。在容灾场景下,CDC 主要实现的是主备间的数据同步,即从主数据库到备数据库的数据实时同步。


source ----------> CDC ----------> sink

Apache SeaTunne CDC

SeaTunnel CDC 的数据同步分为两种:


  • 快照读:读取表的历史数据

  • 增量跟踪:读取表的增量日志更改数据

2.1 无锁快照同步

无锁快照同步阶段,为什么强调无锁,是因为现有的 CDC 平台在进行历史数据的同步时可能会进行锁表操作,例如 Debezium。快照读阶段就是对数据库的历史数据库进行同步的过程,其基本概述流程如下:


storage------------->splitEnumerator----------split---------->reader                            ^                                   |                            |                                   |                            \-----------------report------------/
复制代码


split 划分:splitEnumerator(split 分发器)按照指定的字段(例如表 id 或唯一键)和步长将表数据划分为多个分片 split。并行处理:每个 split 通过路由算法分配给不同的 reader 进行并行读取,一个 reader 会占用一个连接。事件反馈:每个 reader 完成 split 读取后会向 splitEnumerator 报告进度。splitEnumerator 会发送给 reader 一个分片,分片的元数据信息如下:


String              splitId         路由idTableId             tableId         表idSeatunnelRowType    splitKeyType    分片基于的字段的类型Object              splitStart      分片读取起点Object              splitEnd        分片读取终点
复制代码


reader 收到 split 信息后会生成相关的 sql 语句,在此之前会记录当前 split 对应到数据库日志 log 的开始位置,等处理完当前 split 后上报 report 给 splitEnumerator,report 内容如下:


String      splitId         分片idOffset      highWatermark   分片对应log的位置,用于后续的校对
复制代码

2.2 增量同步

增量同步阶段是基于上述快照读取阶段后,在源数据库发生变化时,实时将变更的数据同步到备数据库,不同的是,此阶段监听的是数据库的 log 日志,例如 mysql 的 bin log。增量跟踪通常是单线程处理,这样可以避免重复拉取 bin log,减轻对数据库的压力,因此该阶段只有一个 reader 工作,只占用一个连接。


data log------------->splitEnumerator----------split---------->reader                            ^                                   |                            |                                   |                            \-----------------report------------/
复制代码


增量同步会合成快照阶段所有 split、table,因此只会存在一个 split,增量同步阶段的 split 信息如下:


String                              splitIdOffset                              startingOffset                  所有split中最小的log startOffset                              endingOffset                    log的结束位置,若无则代表是持续的,例如增量阶段List<TableId>                       tableIdsMap<TableId, Offset>                tanleWatermarks                 所有split的watermarkList<CompletedSnapshotSplitInfo>    completedSnapshotSplitInfos     快照阶段读取的split细节信息
复制代码


其中 CompletedSnapshotSplitInfo 的具体字段如下:


String              splitIdTableId             tableIdSeatunnelRowType    splitKeyTypeObject              splitStartObject              splitEndOffset              watermark       对应了report中的highWatermark
复制代码


增量阶段的 split 包含了快照阶段所有 split 的 watermark,会去从其中选出一个合适的位置进行增量同步,这个合适位置就是最小的 watermark。


三、Exactly-once 无论是快照读还是增量读,同步的过程中数据库可能也在经历变化,如何保证 exactly-once?

3.1 快照读阶段

在快照读阶段,例如某个 split 在同步的过程中,这段 split 中的数据发生了变换,例如下图操作,插入一条 k3,更新 k2,删除 k1,如果在读的过程中不做任务标识,那么这部分的更新信息就会丢失,seatunnel 的做法是:


在 split 读取之前首先去数据库查一下 bin log 位置:low watermark


读取 split{start, end}数据


再记录一下高水位 high watermark


如果 high = low 说明在读取该 split 期间,该 split 的数据没有发生变化;如果(high - low) > 0,说明在处理的过程中发生了数据变化,会进行如下操作:①将读到的 split 数据在内存中建立内存表缓存;②将 low watermark~high watermark 的变更;③按顺序、主键重放操作到内存表


报告 report high watermark


          insert k3      update k2      delete k1                |               |               |                v               v               v bin log --|---------------------------------------------------|-- log offset      low watermark                                     high watermark
CDC读到的数据: k1 k3 k4 | 重放 v真实的数据: k2 k3' k4
复制代码

增量阶段

在增量阶段开始之前首先会对上一个步骤的所有 split 做校验,因为在 split 和 split 之间的间隙也有可能出现数据更新,例如在 split1 和 split2 之间插入了若干条记录,在快照阶段就会遗漏掉,对于这种 split 之间的数据回捞,seatunnel 的做法是:


从所有的 split 的 report 中找到最小的 watermark,作为 start watermark,开始读取 log。每读一条 log 都去 completedSnapshotSplitInfos 中找该条数据是否在某个 split 被处理过了,如果没有被处理过,说明是 split 间隙数据,应该被重新修正。当表过滤完后,可以从 completedSnapshotSplitInfos 中删除,继续处理剩余的表。直到所有的 split 都校验结束,就进入到了完全的增量阶段。


    |------------filter split2-----------------|          |----filter split1------|                  data log -|-----------------------|------------------|----------------------------------|- log offset        min watermark      split1 watermark    split2 watermark                    max watermark    
复制代码

断点续传

如果做到暂停恢复?分布式快照算法(Chandy-Lamport):


假设系统中包含了两个进程 p1 和 p2,p1 进程状态包含三个变量 X1 Y1 Z1,p2 包含了三个变量 X2 Y2 Z2,初始状态如下:


p1                                  p2X1:0                                X2:4Y1:0                                Y2:2Z1:0                                Z2:3
复制代码


此时由 p1 发起全局 snapshot 记录,p1 先记录本身的进程状态,然后向 p2 发送 marker 信息。在 marker 信息到达 p2 之前,p2 向 p1 发送 message M。


p1                                  p2X1:0     -------marker------->      X2:4Y1:0     <---------M----------      Y2:2Z1:0                                Z2:3
复制代码


p2 收到 p1 发送来的 marker 信息后,记录自己的状态,然后 p1 收到 p2 之前发送来的 message M,由于 p1 已经做了 local snapshot 了,所以 p1 只需要记录 M。,所以最终的 snapshot 如下:


p1 M                                p2X1:0                                X2:4Y1:0                                Y2:2Z1:0                                Z2:3
复制代码


在 SeaTunnel CDC 的过程中,marker 同发送给所有的 reader、splitEnumerator、writer 等节点都会保存自己的内存状态。

发布于: 刚刚阅读数: 4
用户头像

白鲸开源

关注

一家开源原生的DataOps商业公司。 2022-03-18 加入

致力于打造下一代开源原生的DataOps 平台,助力企业在大数据和云时代,智能化地完成多数据源、多云及信创环境的数据集成、调度开发和治理,以提高企业解决数据问题的效率,提升企业分析洞察能力和决策能力。

评论

发布
暂无评论
3分钟搞懂 Apache SeaTunnel CDC 数据同步_开源_白鲸开源_InfoQ写作社区