Flink-To-Paimon 2pc写入机制

240 阅读5分钟

1.结论:Paimon的写入提交机制和Flink的Checkpoint机制紧密绑定

  1. Paimon的LSM-Tree

    •  WriteBuffer / SortBuffer:即内存中的 MemTable。数据写入时首先进入这里。
    •  Sorted Run:从内存刷盘后形成的有序数据文件。每个 Sorted Run 内部按主键排序。
    •  Levels:LSM-Tree 的分层结构。L0 层的不同文件之间主键范围可能重叠,而 L1 及更高层的文件之间主key范围互不重叠。这种结构使得查询在高层级可以非常高效地定位数据。
    • MergeTreeWriter:负责将内存中的数据刷写到磁盘,形成新的 Sorted Run。
    • MergeTreeCompactManager:后台合并任务的调度中心。它会根据预设的策略(如文件数量、空间放大率),不断地触发合并任务,维持 LSM-Tree 的健康状态。
  2. 数据写缓冲:Flink将数据发送到Paimon的Sink算子,会先根据主键计算所属的bucket,然后数据发送给处理该桶的Writer实例,先写入到内存的写缓冲MemTable(这里是WriteBuffer)

    • 配置write-buffer-size:控制每个 Writer 的写缓冲大小。增大此值可以减少刷盘频率,提升吞吐,但会增加内存消耗和 Checkpoint 的时长,通常设置为256M~1G
    • 配置write-buffer-spillable:: 当设置为 true 时,如果写缓冲耗尽,数据可以被溢出(Spill)到本地磁盘,避免因反压(Back-Pressure)导致整个流处理作业阻塞。
  3. 预提交(Pre-Commit) :当 Flink 开始一个 Checkpoint 时,所有的 Paimon Writer 会刷盘(Flush)其内存缓冲中的数据,生成新的 L0 层文件。这些文件及其元数据(被称为 DataFileMeta)被发送给提交器(Committer)。

    • Flush时,MemTable中的所有数据会按照主键排序,然后再写入到一个新的数据文件Sorted Run,并被放置在LSM-Tree的L0层,L0 层的特点是其内部的不同文件之间可能存在主键范围的重叠
  4. 全局提交(Global Commit) :做 Checkpoint 期间,JobManager 会通知 Paimon 的全局提交器(Global Committer)。全局提交器会执行以下原子操作:

    1.  生成新的 Manifest:将本次 Checkpoint 产生的所有新数据文件的元数据写入一个新的清单文件(Manifest File)。
    2.  创建新的 Snapshot:创建一个新的快照文件,该文件指向新生成的清单文件,并记录本次提交的其它元信息,
    3.  将snapshot、manifest、datfile关联起来

      注意:只有当创建了Snaoshot的时候,写入的文件才可见;若在提交过程中发生任何失败(例如:JobManager 崩溃),快照文件没有被创建,那么这部分写入的数据不会对用户可见,从而避免了“读脏数据”)

  5. 后续压缩(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

流程图如下:

https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/39c5740215854abd83cba6f055e41156~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgZXhwZWN0N2c=:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMzUxNDQ3MTM4NzIzNTczNSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1750844780&x-orig-sign=wUmQuwp8Ff32q1VpegVXSHj5OTk%3D

  1. MySQL CDC Sourceuniform-read snapshot 和 incremental data,同时读取快照数据 和读取增量数据。SnapshotReaderBinlogReader
  2. Paimon Sink将数据写入 bucket 级别的 Paimon 表中。其中的 the will trigger compaction 异步。CompactManager
  3. Committer Operator是负责提交快照和过期快照的单一实例。

《1》CDC干了啥

https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/63d65cc81b834b06b6558d982efa770b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgZXhwZWN0N2c=:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMzUxNDQ3MTM4NzIzNTczNSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1750844780&x-orig-sign=6qPoEVSWzzuqoxM9g12ebDh29dU%3D

MySQL Cdc Source读取快照和增量数据,并在规范化后将其发送到下游。

《2》paimon sink干了啥

https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/c3164e8f685a4011a2e76991c17c9b2a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgZXhwZWN0N2c=:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMzUxNDQ3MTM4NzIzNTczNSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1750844780&x-orig-sign=Xn8sf3zyBz7dpJBQB%2FV%2FMtQm%2BsA%3D

Paimon Sink首先在基于堆的 LSM 树中缓冲new record,并在内存缓冲区满了开始flush刷写到磁盘,形成L0层文件。

注意,写入的每个数据文件都是一个排序好的,按顺序执行。此时,manifest和snapshot还没有创建,数据并不可见在 Flink 检查点发生之前,将flush所有缓冲区的记录并向下游发送可提交消息。Paimon SinkCommitter Operator他开始真正开始提交时发生在做checkpoint的时期。

《3》committer operator干了啥

https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/68a730fa489c49f397d427625998afa0~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgZXhwZWN0N2c=:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMzUxNDQ3MTM4NzIzNTczNSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1750844780&x-orig-sign=M1xaqo7Luo9xSQrk1Vx2RI30ANY%3D

在 checkpoint 期间,将创建一个新快照并将其与清单列表相关联,以便快照 包含有关表中所有数据文件的信息。Committer Operator

注意:此时数据文件才可见,若配置了write-only=true,那么此时的数据文件是L0层,后续需要compaction才会形成L1及更高层

如果开启了压缩策略,并且达到了压缩条件,那么流程如下

https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/2001a75a0b964c2ba4a42cf44ca9f824~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgZXhwZWN0N2c=:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMzUxNDQ3MTM4NzIzNTczNSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1750844780&x-orig-sign=Fe6ScIVcw5WFZZFw1kMW3VtQmdI%3D

进行异步压缩操作,并且由(相关操作)生成的可提交文件包含了先前文件合并文件的信息,因此,(系统)能够构建相应的清单条目。在这种情况下,在 Flink 检查点期间可能会生成两个快照,一个是针对已写入数据的快照(追加类型的快照),另一个是针对压缩操作的快照(压缩类型的快照)。如果在检查点间隔期间没有写入数据文件,那么只会创建追加类型的快照。(压缩管理器提交操作符)会根据快照过期情况进行检查,并对标记的数据文件执行物理删除操作。

也就是说在压缩的时候,其实没有真正的删除文件,只是逻辑删除文件了。

但是当snapshot过期后,就是真正的物理删除文件了