外观
补数 / 重跑 / 追数怎么做才安全
难度与前置
难度:中级
前置:知道按 dt 分区重跑;清楚下游依赖边。
读完能做什么:区分补数/重跑/追数,选安全窗口与互斥策略,级联下游并量化验收。
适用场景
- 源系统补发历史、口径变更、Bug 修数后要回刷某段日期
- 调度失败多天,需要「追数」把缺口补上且不影响今日 SLA
- 重跑后对账、报表、下游主题不一致,需要规范操作
不适用:
- 实时状态表的任意 rewind(先看 Checkpoint / 幂等语义)
- 无分区、只能全表锁写的小表(先改成分区或版本表再谈补数)
- 「改一行手工 update 生产」的临时救火(必须进变更单与回刷流程)
真实场景(一条)
渠道侧补发 T-7~T-3 消耗明细,ODS 已接入。若只重跑 ODS:
- DWD/DWS/ADS 仍是旧数 → 对账 ADS 继续差
- 若与今日日常调度并行写同一
dt→ 偶发半份分区 - 若一次性重跑 30 天无限流 → 打满集群,今日 P0 日报违约
目标:按日窗口补数、上游→下游级联、与日常实例互斥、每层验收后再往下。
怎么做(步骤清单)
1. 先分清三种操作
| 操作 | 含义 | 典型触发 |
|---|---|---|
| 重跑 | 同一逻辑、同一 dt 再跑一遍 | 任务失败、瞬时资源问题 |
| 补数 | 源或口径变更,回刷历史分区 | 补文件、修 Bug、口径切换 |
| 追数 | 积压多日未跑,按序赶进度 | 集群故障、上游连续延迟 |
口诀:重跑保当日,补数改历史,追数清债务——都要幂等 + 互斥。
2. 划定窗口与影响面
补数单最少写清:
- 表与分区范围:
dt in [start, end] - 原因与口径是否变化(变了要同步指标字典)
- 下游清单(从依赖图导出,禁止口头「应该没影响」)
- 是否冻结对外:补数期间 ADS 是否标「修订中」
- 回滚方式:旧分区备份 / 版本路径 / 可再跑旧代码
text
# 影响面示意
ods_ad_spend_di [T-7,T-3]
→ dwd_ad_spend_detail_di
→ dws_ad_channel_play_1d
→ ads_ad_daily_report_1d, ads_ad_recon_channel_1d3. 互斥:补数 vs 日常调度
- 对将补的
dt:暂停或锁定日常写同一分区的实例 - 今日
biz_date的日常任务与历史补数队列分资源队列(避免追数挤爆 P0) - 同一分区同时只允许一个 Writer(调度互斥锁 / 表级约定 / 成功文件令牌)
bash
# 示意:补数前对目标 dt 打锁(平台能力不同,语义一致即可)
# lock_partition --table dwd_ad_spend_detail_di --dt 2026-09-20 --owner backfill_ticket_10244. 按层级联,一层一验收
顺序:ODS → DWD → DIM 关联日 → DWS → ADS。禁止「只补 ADS 从 ODS 直算」。
每层验收最小集:
sql
-- 行数与金额相对日常基线(同口径)
SELECT dt, COUNT(*) AS cnt, SUM(cost_amount) AS cost
FROM dwd_ad_spend_detail_di
WHERE dt BETWEEN '${start}' AND '${end}'
GROUP BY dt
ORDER BY dt;sql
-- 主键唯一
SELECT dt, COUNT(*) AS dup_keys
FROM (
SELECT dt, bill_id, COUNT(*) c
FROM dwd_ad_spend_detail_di
WHERE dt BETWEEN '${start}' AND '${end}'
GROUP BY dt, bill_id
HAVING COUNT(*) > 1
) t
GROUP BY dt;
-- 期望:dup_keys = 0一层 PASS 再触发下一层同窗口任务(可用补数工作流自动级联)。
5. 追数节奏:限流 + SLA 保护
- 追数批次:例如每次 1~3 个
dt,或按集群空闲窗口 - 保今日 P0:追数队列低于日常优先级;P0 窗口内暂停追数
- 记录水位:
catchup_watermark(已追到的最大dt),看板可见
text
catchup_plan:
range: [T-10, T-1]
batch_size: 2
pause_windows: ["08:30-10:00"] # 保护早报 SLA
priority: low6. 幂等写入约定(与数仓域对齐)
- 分区表优先:
INSERT OVERWRITE该dt,或动态分区覆盖 - 有主键合并语义的表:按键 upsert,避免追加造成翻倍
- 重跑前确认:不会追加重复行(见 幂等回刷)
常见坑(至少牢记这些)
只重跑最下游
ADS 修好了,DWD 仍错,下周对账又炸。必须从变更发生层起级联。补数与日常双写同一分区
结果非左非右。先锁分区或停日常实例。大窗一口吃完
30 天并行打满 YARN/K8s,今日 SLA 全军覆没。限流 + 保 P0 窗口。口径变更不改字典、不标修订
业务对比历史曲线「突然跳变」却无说明。补数单同步口径版本与对外公告。追数打乱时间顺序且下游有状态依赖
某些累计指标依赖「按日顺序」。无状态依赖则严格按dt升序追;无则可并行但要验证。
如何验收(可量化)
- [ ] 补数单含:窗口、原因、下游清单、互斥方式、回滚
- [ ] 目标
dt无双 Writer;日常实例已暂停或锁生效 - [ ] 自变更层起每层 SQL 验收 PASS 后才下游
- [ ] 主键重复 = 0;与源/渠道对账差额在阈值或可解释
- [ ] 追数期间今日 P0 就绪时刻未因追数违约(或有批准的例外单)
sql
-- 补数窗口:DWD vs DWS 对齐
SELECT d.dt, d.cost_dwd, s.cost_dws, d.cost_dwd - s.cost_dws AS diff
FROM (
SELECT dt, SUM(cost_amount) AS cost_dwd
FROM dwd_ad_spend_detail_di
WHERE dt BETWEEN '${start}' AND '${end}' AND is_valid = true
GROUP BY dt
) d
JOIN (
SELECT dt, SUM(cost_amount) AS cost_dws
FROM dws_ad_channel_play_1d
WHERE dt BETWEEN '${start}' AND '${end}'
GROUP BY dt
) s ON d.dt = s.dt
ORDER BY d.dt;
-- 期望:|diff| 在约定舍入误差内bash
# 验收:补数锁已释放;catchup_watermark 推进到 end
# show_partition_locks --table dwd_ad_spend_detail_di
# 期望:无 backfill 残留锁首次补数或值班不熟时,先按 补数演练 runbook 干跑再真补;本篇管策略,演练篇管上场清单。
回刷范围与是否该补,先看 改表前影响评估;本篇管补数/重跑/追数怎么安全执行。
相关面试题
占位:与题库小程序对齐后补链接(建议关联:补数怎么做、重跑幂等、追数与 SLA)。
改写说明:结构参考 Wood 原创调度/回刷实践,已改写成可执行清单;未包含未公开公司工单系统与集群名。