1.结论:Paimon的写入提交机制和Flink的Checkpoint机制紧密绑定
-
Paimon的LSM-Tree
- WriteBuffer / SortBuffer:即内存中的 MemTable。数据写入时首先进入这里。
- Sorted Run:从内存刷盘后形成的有序数据文件。每个 Sorted Run 内部按主键排序。
- Levels:LSM-Tree 的分层结构。L0 层的不同文件之间主键范围可能重叠,而 L1 及更高层的文件之间主key范围互不重叠。这种结构使得查询在高层级可以非常高效地定位数据。
- MergeTreeWriter:负责将内存中的数据刷写到磁盘,形成新的 Sorted Run。
- MergeTreeCompactManager:后台合并任务的调度中心。它会根据预设的策略(如文件数量、空间放大率),不断地触发合并任务,维持 LSM-Tree 的健康状态。
-
数据写缓冲:Flink将数据发送到Paimon的Sink算子,会先根据主键计算所属的bucket,然后数据发送给处理该桶的Writer实例,先写入到内存的写缓冲MemTable(这里是WriteBuffer)
- 配置
write-buffer-size:控制每个 Writer 的写缓冲大小。增大此值可以减少刷盘频率,提升吞吐,但会增加内存消耗和 Checkpoint 的时长,通常设置为256M~1G - 配置
write-buffer-spillable:: 当设置为true时,如果写缓冲耗尽,数据可以被溢出(Spill)到本地磁盘,避免因反压(Back-Pressure)导致整个流处理作业阻塞。
- 配置
-
预提交(Pre-Commit) :当 Flink 开始一个 Checkpoint 时,所有的 Paimon Writer 会刷盘(Flush)其内存缓冲中的数据,生成新的 L0 层文件。这些文件及其元数据(被称为 DataFileMeta)被发送给提交器(Committer)。
- Flush时,MemTable中的所有数据会按照主键排序,然后再写入到一个新的数据文件Sorted Run,并被放置在LSM-Tree的L0层,L0 层的特点是其内部的不同文件之间可能存在主键范围的重叠
-
全局提交(Global Commit) :做 Checkpoint 期间,JobManager 会通知 Paimon 的全局提交器(Global Committer)。全局提交器会执行以下原子操作:
- 生成新的 Manifest:将本次 Checkpoint 产生的所有新数据文件的元数据写入一个新的清单文件(Manifest File)。
- 创建新的 Snapshot:创建一个新的快照文件,该文件指向新生成的清单文件,并记录本次提交的其它元信息,
- 将snapshot、manifest、datfile关联起来
注意:只有当创建了Snaoshot的时候,写入的文件才可见;若在提交过程中发生任何失败(例如:JobManager 崩溃),快照文件没有被创建,那么这部分写入的数据不会对用户可见,从而避免了“读脏数据”)
-
后续压缩(Compaction):已完成全局提交后,L0 层的文件数量会不断增加。过多的文件不仅会降低查询性能(读放大),还会增加元数据管理的开销。因此,Paimon 引入了Compaction机制,它会将多个Sorted Run进行合并成新的或更高层的数据文件,并产生changelog,这样下游消费者可以流式消费
- 合并过程:将多个Sorted Run(同一层或不同层),将他们的数据进行多路归并排序(Paimon采用的是最小堆(Min-Heap)和败者树(Loser Tree),败者树通常能提供更好的性能,因为它减少了比较的次数)
- 合并策略:类似RocksDB的Universal Compaction策略
- 相关配置
- 配置
num-sorted-run.compaction-trigger:当一个桶内的 Sorted Run 文件数量达到此阈值时,触发一次合并操作。这是控制合并频率的核心参数,默认是5。 - 配置
num-sorted-run.stop-trigger: 当文件数量达到此阈值时,会暂停写入,以强制等待合并完成。这是防止文件数量失控、导致查询性能严重下降的保护机制。
- 配置
2.流程图
介绍今天的三位成员,分别是CDC、Paimon Sink、Committer Operator
流程图如下:
MySQL CDC Sourceuniform-read snapshot 和 incremental data,同时读取快照数据 和读取增量数据。SnapshotReaderBinlogReaderPaimon Sink将数据写入 bucket 级别的 Paimon 表中。其中的 the will trigger compaction 异步。CompactManagerCommitter Operator是负责提交快照和过期快照的单一实例。
《1》CDC干了啥
MySQL Cdc Source读取快照和增量数据,并在规范化后将其发送到下游。
《2》paimon sink干了啥
Paimon Sink首先在基于堆的 LSM 树中缓冲new record,并在内存缓冲区满了开始flush刷写到磁盘,形成L0层文件。
注意,写入的每个数据文件都是一个排序好的,按顺序执行。此时,manifest和snapshot还没有创建,数据并不可见。在 Flink 检查点发生之前,将flush所有缓冲区的记录并向下游发送可提交消息。
Paimon SinkCommitter Operator他开始真正开始提交时发生在做checkpoint的时期。
《3》committer operator干了啥
在 checkpoint 期间,将创建一个新快照并将其与清单列表相关联,以便快照 包含有关表中所有数据文件的信息。Committer Operator
注意:此时数据文件才可见,若配置了
write-only=true,那么此时的数据文件是L0层,后续需要compaction才会形成L1及更高层
如果开启了压缩策略,并且达到了压缩条件,那么流程如下
进行异步压缩操作,并且由(相关操作)生成的可提交文件包含了先前文件合并文件的信息,因此,(系统)能够构建相应的清单条目。在这种情况下,在 Flink 检查点期间可能会生成两个快照,一个是针对已写入数据的快照(追加类型的快照),另一个是针对压缩操作的快照(压缩类型的快照)。如果在检查点间隔期间没有写入数据文件,那么只会创建追加类型的快照。(压缩管理器提交操作符)会根据快照过期情况进行检查,并对标记的数据文件执行物理删除操作。
也就是说在压缩的时候,其实没有真正的删除文件,只是逻辑删除文件了。
但是当snapshot过期后,就是真正的物理删除文件了