3、补数范围定义:时间范围补数、分区补数、表级补数、任务级补数
补数范围怎么定?这是设计补数机制时第一个要拍板的事。
我见过不少团队,一上来就写死一个「重跑昨天数据」的逻辑。结果业务说「我要补上个月的数据」,运维说「我只想重跑某个坏掉的分区」,老板说「整个表数据都不对,给我全量重来」——好嘛,一个补数接口根本不够用。
所以,补数范围必须分层设计。我个人习惯把它拆成四个维度:时间范围、分区、表级、任务级。下面一个个说。
3.1 时间范围补数
这是最常用的补数方式。说白了,就是指定一个时间窗口,把窗口内的数据重新跑一遍。
时间范围补数通常包含三个参数:
- 开始时间(biz_date_from)
- 结束时间(biz_date_to)
- 时间粒度(如天、小时、分钟)
举个例子:
{
"type": "time_range",
"biz_date_from": "2024-01-01",
"biz_date_to": "2024-01-10",
"granularity": "day"
}
这个配置的意思是:补 2024-01-01 到 2024-01-10 共 10 天的数据,每天作为一个独立补数单元。
3.2 分区补数
分区补数,是针对 Hive、ClickHouse 这类分区表设计的。你想想看,一张表可能有几百个分区,全量重跑太慢了。我只想修某个坏掉的分区,怎么办?
分区补数就是干这个的。它允许你指定一个或多个分区键值,只重跑这些分区。
{
"type": "partition",
"table": "ods_order",
"partitions": ["dt=2024-01-05", "dt=2024-01-07"]
}
这里只重跑 dt=2024-01-05 和 dt=2024-01-07 两个分区,其他分区不动。
3.3 表级补数
表级补数,就是整张表全部重跑。听起来简单粗暴,但确实有它的用武之地。
什么时候需要表级补数?
- 数据源全量重导,比如从业务库重新拉了一整份数据
- 表结构变更,比如新增了字段,需要重新计算历史数据
- 数据质量太差,修都修不过来,干脆全量覆盖
表级补数的配置通常很简单:
{
"type": "table",
"table": "dws_order_daily",
"overwrite": true
}
overwrite 参数很关键。true 表示先删后写,false 表示增量覆盖。我建议默认用 true,否则可能出现重复数据。
3.4 任务级补数
任务级补数,是最灵活的一种。它不关心表,也不关心分区,只关心「任务实例」。
你可以指定一个任务 ID,以及这个任务的历史运行时间点,然后重新执行。比如:
{
"type": "task",
"task_id": "etl_order_merge",
"run_ids": ["run_20240105_030000", "run_20240106_030000"]
}
这种模式特别适合那种「任务逻辑变了,需要重跑历史实例」的场景。我记得有一次,数据清洗规则改了,之前跑过的所有实例都得重来。用任务级补数,直接拉出过去 30 天的运行记录,批量重跑,一天就搞定了。
3.5 四种补数范围对比
| 补数类型 | 粒度 | 适用场景 | 风险等级 |
|---|---|---|---|
| 时间范围补数 | 时间窗口 | 常规数据修复、周期性重跑 | 低 |
| 分区补数 | 分区键 | 分区表局部修复 | 中 |
| 表级补数 | 整张表 | 全量重导、结构变更 | 高 |
| 任务级补数 | 任务实例 | 逻辑变更、历史重跑 | 中 |
3.6 补数范围选择策略
实际项目中,这四种补数范围不是互斥的。我通常建议把它们组合起来,形成一个「补数范围矩阵」。
举个例子:
- 用户选择「时间范围 + 分区」,表示在某个时间范围内,只重跑指定分区
- 用户选择「任务级 + 时间范围」,表示重跑某个任务在指定时间内的所有实例
这样做的好处是,补数系统可以覆盖 90% 以上的数据修复场景。剩下的 10%,要么是特殊情况手动处理,要么是系统设计没覆盖到。
3.7 补数范围的核心逻辑图
下面这张图展示了四种补数范围的关系和选择流程:
嗯,这张图基本把补数范围的选择逻辑讲清楚了。从补数请求开始,先选类型,再经过冲突检测和优先级裁决,最后生成补数任务。实际项目中,我还会加一个「补数范围预览」步骤,让用户在执行前能看到哪些分区、哪些实例会被重跑,避免误操作。