Paimon 与 ForSt 场景选型分析
1. 背景与核心定位
当作业中 payload 体积极大,且访问模式为"低频积攒、按批触发"时,将其全部塞入 Flink Managed State 会导致 Checkpoint 耗时剧增、RocksDB 性能下降。此时面临两种架构选型:
- Paimon + 小索引 State
- 定位:主数据存储(外部表)。
- 机制:Flink State 仅托管控制元数据(rowkey、batch 边界、timer、count),实际 payload 写入 Paimon。触发时通过 Paimon 点查补齐数据。
- ForSt + 全量 Payload State
- 定位:Operator 私有工作状态(Managed State)。
- 机制 :通过存算分离(Disaggregated State)和异步状态 API(State V2),将大状态托管至远端存储,复用本地磁盘作为缓存。参考 ForStStateBackend.java#L89-L96 。
2. Paimon 方案解析:外部表 + 状态索引
2.1 核心优势:生命周期解耦与冷热分层
- Checkpoint 轻量化:仅保存元数据,规避了大 payload 的快照搬运开销。
- 数据资产复用:写入 Paimon 的 payload 成为标准表格式数据(带 Snapshot、Manifest、LSM 树),可被 SQL 查询、离线回溯和其他链路直接复用。
- 冷热分离:热的控制状态在 Flink,冷的业务明细在 Paimon。
2.2 点查性能机制
Paimon 的 Lookup 并非每次裸扫远程文件,而是基于文件级元数据与本地缓存:
- 沿 LSM Levels 查找主键。
- 定位到目标
DataFileMeta后,若本地无对应LookupFile,则拉取远程文件并在本地构建索引。 - 后续查询直接命中本地 Caffeine 缓存。
代价:增加了一跳外部 Lookup,查询性能强依赖于本地缓存命中率和文件 Compaction 布局。
3. 状态与数据分离的语义风险 (CRITICAL)
当 payload 脱离 Flink Checkpoint 闭合边界后,框架原生的 Exactly-Once 语义被破坏。若业务要求"不丢、不重、严格可重现",必须在业务层自行兜底。
3.1 少数据(缺失可见性)
- 现象:rowkey 已记入 State 且 Checkpoint 成功,但对应 payload 在 Paimon 中尚未 Commit 或对当前视图不可见。任务崩溃恢复后按 rowkey 查不到数据。
- 业务影响:批次聚合结果偏小、明细缺行。
- 应对:引入缺失重试机制、等待下一个 Snapshot 或按批次强一致对齐。
3.2 重复处理与防重
- 现象:payload 已写入 Paimon 并触发下游输出,但在 State 快照前任务崩溃。恢复后 Source 重放,导致同一批数据再次写入并触发。
- 业务影响:重复发通知、重复结算。
- 应对 :引入全局唯一
batchId,配合下游幂等 Sink 或输出去重键。
3.3 跨批污染与版本漂移
- 现象 :恢复后直接按
userId查最新表视图,查到了失败后新摄入的数据;或 rowkey 对应的记录已被更新。 - 业务影响:上一批混入下一批数据,或查到了更新后的值而非进入该批次时的原始值。
- 应对 :绑定精确边界(如 rowkey 列表、
batchId、Snapshot ID),冻结读取视图。
4. 场景演练:100 条或 12 小时触发
场景:每个 user 从首条数据开始,积攒 100 条或满 12 小时触发,随后按 rowkey 查回 payload 并输出。
4.1 单 Job 架构的局限
- 流程:单算子内同步完成写 Paimon、记 rowkey 入 State、注册 Timer、满足条件后触发回查。
- 痛点:写表可见性与 State 快照时序深度耦合。Timer 触发极易遭遇上述"少数据"风险(查不到刚写入的数据)。
4.2 双 Job 架构(推荐实践)
通过拆分职责,物理隔离"写表"与"聚批":
- Job1(写表):仅负责将原始输入写入 Paimon,确保数据落盘并生成 Snapshot。
- Job2(聚批与触发) :仅消费 Paimon 中 已可见 的 Changelog 或记录。维护
count、rowkey list、timer和batchId。满足条件后按 rowkey 回查并输出。 - 收益:彻底解决"State 记了但表里查不到"的问题。Job2 的 Checkpoint 极轻量。
- 残留局限 :双 Job 无法自动解决端到端 Exactly-Once。仍需在 Job2 依赖
batchId和下游幂等来防重和防串批。
5. 最终选型决策
5.1 选择 Paimon + 小索引 State
适用于 冷数据批量回查 模式:
- 核心痛点是 Checkpoint 体积过大。
- payload 访问频率低,仅在批次闭合时集中读取。
- 数据本身具有业务价值,需要被外部复用。
- 业务能接受最终一致,或有能力自行实现
batchId和幂等逻辑兜底。
5.2 选择 ForSt + 全量 Payload State
适用于 热状态高频访问 模式:
- payload 每来一条都需要参与计算或更新。
- 高频点查、对单次读取延迟敏感。
- 状态仅服务于当前作业,生命周期与作业强绑定,无需对外暴露。参考 disaggregated_state.md#L39-L52 。
- 强依赖 Flink 原生 Managed State 提供的 Exactly-Once 闭合语义。