分区标记完成--实现流到批的转化

3 阅读4分钟

分区标记完成,流批一体?

  1. 首先,您需要定义分区的时间解析器和分区之间的时间间隔,以便确定何时可以正确地将分区标记为 done。
  2. 其次,您需要定义 idle-time,它决定了分区没有新数据需要多长时间。 然后它将被标记为 DONE。
  3. 第三,默认情况下,partition mark done 会创建一个 SUCCESS 文件, SUCCESS文件的内容是 json,包含 和 ,它们可以帮助你了解是否有延迟数据。您还可以配置其他作,例如 ,使用 Produce done partition 进行分区。文件内容如下,下游系统通过比较这两个时间戳可判断是否存在延迟数据(如 modificationTime > creationTime + time-interval则判定为延迟数据,可用insert overwrite去解决延迟数据的影响)。
{
  "creationTime": "2024-04-22T00:00:00Z",
  "modificationTime": "2024-04-22T14:30:00Z" -- 这个值不是表中的dt,而是系统通过文件系统的最后写入时间来的
}
CREATE TABLE my_partitioned_table (
    f0 INT,
    f1 INT,
    f2 INT,
    ...
    dt STRING
) PARTITIONED BY (dt) WITH (
    'partition.timestamp-formatter'='yyyyMMdd', -- 将分区字段dt转为时间戳
    'partition.timestamp-pattern'='$dt',
    'partition.time-interval'='1 d',  -- 确定分区的时间跨度
    'partition.idle-time-to-done'='15 m',  -- 判定分区多长时间无新数据写入标记为done,是给离线那边做批任务启动的标记  技术原理:通过监控文件系统的 modificationTime 判断活跃状态,结合水印机制处理乱序数据。
    'partition.mark-done-action'='done-partition'
);

假设写入数据 dt='20250421',但文件系统实际写入时间为 2025-04-22T00:02:00(即 modificationTime=2025-04-22T00:02:00)

那么分区 dt=20250421 的元数据如下:

  • creationTime = 2025-04-21T00:00:00Z
  • modificationTime = 2025-04-22T00:02:00Z(比预期时间窗口 超出2分钟

而等到2025-04-22 00:17(2+15):00的时候都没有再来数据往20250421分区写了,那么就会把20250421分区标记为done,可用于执行离线批任务

《1》系统行为逻辑

阶段触发条件具体动作
时间窗口关闭creationTime + time-interval = 2025-04-21T23:59:59Z系统认为该分区的 理论时间窗口已结束时间窗口仅用于计算分区的理论生命周期,不会自动校验数据的事件时间是否在窗口内。
延迟写入检测modificationTime > creationTime + time-interval(超2分钟)在元数据中标记该分区存在 延迟数据(但不会自动扩展时间窗口)
标记完成触发最后一次写入时间 20250422 00:02:00 ≥ 20250421 23:59:59 后,等待 idle-time-to-done=15m实际标记完成时间为 2025-04-22T00:17:00Z(需满足属于20250422分区的,在15分钟内都无新数据)
下游任务调度检测到 _SUCCESS 文件生成(包含最终 modificationTime)在 00:17:00 后启动离线任务(而非 00:02:00)

《2》结论

  • 离线任务启动时间:由 idle-time-to-done 决定(示例中为 00:17:00),与 modificationTime 超界时间无直接关系,然后离线任务会去拿取分区为21号的所有数据(包括那条22号来的的延迟数据)
  • 延迟数据影响modificationTime 超界会记录在 _SUCCESS 文件中,但 不会阻止标记完成
  • 数据完整性风险:超界写入的数据本应该属于下一个分区(如 2025-04-22),但被错误写入历史分区(如 2025-04-21),从而影响21号的数据结果

3.技术解决方案

(1) 写入端约束(根源治理)

-- 启用写入时间校验(需Paimon 2.3+)
ALTER TABLE my_table SET (
    'partition.time-validator' = 'strict'  -- 可以在建表的时候指定,默认是none
);
  • 严格模式:拒绝写入 modificationTime > creationTime + time-interval 的数据
  • 警告模式:允许写入但记录审计日志('partition.time-validator' = 'warn'

(2) 处理端补偿(事后修复)

# 方1:下游任务增加时间窗口过滤
spark.read.format("paimon")
    .load("my_table")
    .filter("dt='20250421' AND event_time BETWEEN '2025-04-21 00:00:00' AND '2025-04-21 23:59:59'")

# 方2:使用Paimon CLI修复分区归属
paimon-cli migrate-partition \
    --source dt=20250421 \
    --target dt=20250422 \
    --filter "event_time >= '2025-04-22 00:00:00'"  # 假设存在隐藏的事件时间字段