2024-03-18 09:18:27 50阅读
CDC(Change Data Capture)是一种用于跟踪数据库库变更事件(插入、更新、删除)中的行级更改,并将事件以发生的顺序通知到其他系统处理。在容灾场景下,CDC主要实现的是主备间的数据同步,即从主数据库到备数据库的数据实时同步。
source ----------> CDC ----------> sink
Seatunnel CDC的数据同步分为两种:
无锁快照同步阶段,为什么强调无锁,是因为现有的CDC平台在进行历史数据的同步时可能会进行锁表操作,例如Debezium。快照读阶段就是对数据库的历史数据库进行同步的过程,其基本概述流程如下:
storage------------->splitEnumerator----------split---------->reader
^ |
| |
\-----------------report------------/
splitEnumerator会发送给reader一个分片,分片的元数据信息如下:
String splitId 路由id
TableId tableId 表id
SeatunnelRowType splitKeyType 分片基于的字段的类型
Object splitStart 分片读取起点
Object splitEnd 分片读取终点
reader收到split信息后会生成相关的sql语句,在此之前会记录当前split对应到数据库日志log的开始位置,等处理完当前split后上报report给splitEnumerator,report内容如下:
String splitId 分片id
Offset highWatermark 分片对应log的位置,用于后续的校对
增量同步阶段是基于上述快照读取阶段后,在源数据库发生变化时,实时将变更的数据同步到备数据库,不同的是,此阶段监听的是数据库的log日志,例如mysql的bin log。增量跟踪通常是单线程处理,这样可以避免重复拉取bin log,减轻对数据库的压力,因此该阶段只有一个reader工作,只占用一个连接。
data log------------->splitEnumerator----------split---------->reader
^ |
| |
\-----------------report------------/
增量同步会合成快照阶段所有split、table,因此只会存在一个split,增量同步阶段的split信息如下:
String splitId
Offset startingOffset 所有split中最小的log start
Offset endingOffset log的结束位置,若无则代表是持续的,例如增量阶段
List<TableId> tableIds
Map<TableId, Offset> tanleWatermarks 所有split的watermark
List<CompletedSnapshotSplitInfo> completedSnapshotSplitInfos 快照阶段读取的split细节信息
其中CompletedSnapshotSplitInfo的具体字段如下:
String splitId
TableId tableId
SeatunnelRowType splitKeyType
Object splitStart
Object splitEnd
Offset watermark 对应了report中的highWatermark
增量阶段的split包含了快照阶段所有split的watermark,会去从其中选出一个合适的位置进行增量同步,这个合适位置就是最小的watermark。
无论是快照读还是增量读,同步的过程中数据库可能也在经历变化,如何保证exactly-once?
在快照读阶段,例如某个split在同步的过程中,这段split中的数据发生了变换,例如下图操作,插入一条k3,更新k2,删除k1,如果在读的过程中不做任务标识,那么这部分的更新信息就会丢失,seatunnel的做法是:
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的做法是:
|------------filter split2-----------------|
|----filter split1------|
data log -|-----------------------|------------------|----------------------------------|- log offset
min watermark split1 watermark split2 watermark max watermark
如果做到暂停恢复?分布式快照算法(Chandy-Lamport):
p1 p2
X1:0 X2:4
Y1:0 Y2:2
Z1:0 Z2:3
p1 p2
X1:0 -------marker-------> X2:4
Y1:0 <---------M---------- Y2:2
Z1:0 Z2:3
p1 M p2
X1:0 X2:4
Y1:0 Y2:2
Z1:0 Z2:3
在Seatunnel CDC的过程中,marker同发送给所有的reader、splitEnumerator、writer等节点都会保存自己的内存状态。
2024-03-18 09:18:27 50阅读
CDC(Change Data Capture)是一种用于跟踪数据库库变更事件(插入、更新、删除)中的行级更改,并将事件以发生的顺序通知到其他系统处理。在容灾场景下,CDC主要实现的是主备间的数据同步,即从主数据库到备数据库的数据实时同步。
source ----------> CDC ----------> sink
Seatunnel CDC的数据同步分为两种:
无锁快照同步阶段,为什么强调无锁,是因为现有的CDC平台在进行历史数据的同步时可能会进行锁表操作,例如Debezium。快照读阶段就是对数据库的历史数据库进行同步的过程,其基本概述流程如下:
storage------------->splitEnumerator----------split---------->reader
^ |
| |
\-----------------report------------/
splitEnumerator会发送给reader一个分片,分片的元数据信息如下:
String splitId 路由id
TableId tableId 表id
SeatunnelRowType splitKeyType 分片基于的字段的类型
Object splitStart 分片读取起点
Object splitEnd 分片读取终点
reader收到split信息后会生成相关的sql语句,在此之前会记录当前split对应到数据库日志log的开始位置,等处理完当前split后上报report给splitEnumerator,report内容如下:
String splitId 分片id
Offset highWatermark 分片对应log的位置,用于后续的校对
增量同步阶段是基于上述快照读取阶段后,在源数据库发生变化时,实时将变更的数据同步到备数据库,不同的是,此阶段监听的是数据库的log日志,例如mysql的bin log。增量跟踪通常是单线程处理,这样可以避免重复拉取bin log,减轻对数据库的压力,因此该阶段只有一个reader工作,只占用一个连接。
data log------------->splitEnumerator----------split---------->reader
^ |
| |
\-----------------report------------/
增量同步会合成快照阶段所有split、table,因此只会存在一个split,增量同步阶段的split信息如下:
String splitId
Offset startingOffset 所有split中最小的log start
Offset endingOffset log的结束位置,若无则代表是持续的,例如增量阶段
List<TableId> tableIds
Map<TableId, Offset> tanleWatermarks 所有split的watermark
List<CompletedSnapshotSplitInfo> completedSnapshotSplitInfos 快照阶段读取的split细节信息
其中CompletedSnapshotSplitInfo的具体字段如下:
String splitId
TableId tableId
SeatunnelRowType splitKeyType
Object splitStart
Object splitEnd
Offset watermark 对应了report中的highWatermark
增量阶段的split包含了快照阶段所有split的watermark,会去从其中选出一个合适的位置进行增量同步,这个合适位置就是最小的watermark。
无论是快照读还是增量读,同步的过程中数据库可能也在经历变化,如何保证exactly-once?
在快照读阶段,例如某个split在同步的过程中,这段split中的数据发生了变换,例如下图操作,插入一条k3,更新k2,删除k1,如果在读的过程中不做任务标识,那么这部分的更新信息就会丢失,seatunnel的做法是:
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的做法是:
|------------filter split2-----------------|
|----filter split1------|
data log -|-----------------------|------------------|----------------------------------|- log offset
min watermark split1 watermark split2 watermark max watermark
如果做到暂停恢复?分布式快照算法(Chandy-Lamport):
p1 p2
X1:0 X2:4
Y1:0 Y2:2
Z1:0 Z2:3
p1 p2
X1:0 -------marker-------> X2:4
Y1:0 <---------M---------- Y2:2
Z1:0 Z2:3
p1 M p2
X1:0 X2:4
Y1:0 Y2:2
Z1:0 Z2:3
在Seatunnel CDC的过程中,marker同发送给所有的reader、splitEnumerator、writer等节点都会保存自己的内存状态。