分区标记完成,流批一体?
- 首先,您需要定义分区的时间解析器和分区之间的时间间隔,以便确定何时可以正确地将分区标记为 done。
- 其次,您需要定义 idle-time,它决定了分区没有新数据需要多长时间。 然后它将被标记为 DONE。
- 第三,默认情况下,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'" # 假设存在隐藏的事件时间字段