Skip to content

补数 / 重跑 / 追数怎么做才安全 ​

难度与前置

难度:中级
前置:知道按 dt 分区重跑;清楚下游依赖边。
读完能做什么:区分补数/重跑/追数,选安全窗口与互斥策略,级联下游并量化验收。

适用场景 ​

  • 源系统补发历史、口径变更、Bug 修数后要回刷某段日期
  • 调度失败多天,需要「追数」把缺口补上且不影响今日 SLA
  • 重跑后对账、报表、下游主题不一致,需要规范操作

不适用:

  • 实时状态表的任意 rewind(先看 Checkpoint / 幂等语义)
  • 无分区、只能全表锁写的小表(先改成分区或版本表再谈补数)
  • 「改一行手工 update 生产」的临时救火(必须进变更单与回刷流程)

真实场景(一条) ​

渠道侧补发 T-7~T-3 消耗明细,ODS 已接入。若只重跑 ODS:

  • DWD/DWS/ADS 仍是旧数 → 对账 ADS 继续差
  • 若与今日日常调度并行写同一 dt → 偶发半份分区
  • 若一次性重跑 30 天无限流 → 打满集群,今日 P0 日报违约

目标:按日窗口补数、上游→下游级联、与日常实例互斥、每层验收后再往下。

怎么做(步骤清单) ​

1. 先分清三种操作 ​

操作含义典型触发
重跑同一逻辑、同一 dt 再跑一遍任务失败、瞬时资源问题
补数源或口径变更,回刷历史分区补文件、修 Bug、口径切换
追数积压多日未跑,按序赶进度集群故障、上游连续延迟

口诀:重跑保当日,补数改历史,追数清债务——都要幂等 + 互斥。

2. 划定窗口与影响面 ​

补数单最少写清:

  1. 表与分区范围:dt in [start, end]
  2. 原因与口径是否变化(变了要同步指标字典)
  3. 下游清单(从依赖图导出,禁止口头「应该没影响」)
  4. 是否冻结对外:补数期间 ADS 是否标「修订中」
  5. 回滚方式:旧分区备份 / 版本路径 / 可再跑旧代码
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_1d

3. 互斥:补数 vs 日常调度 ​

  • 对将补的 dt:暂停或锁定日常写同一分区的实例
  • 今日 biz_date 的日常任务与历史补数队列分资源队列(避免追数挤爆 P0)
  • 同一分区同时只允许一个 Writer(调度互斥锁 / 表级约定 / 成功文件令牌)
bash
# 示意:补数前对目标 dt 打锁(平台能力不同,语义一致即可)
# lock_partition --table dwd_ad_spend_detail_di --dt 2026-09-20 --owner backfill_ticket_1024

4. 按层级联,一层一验收 ​

顺序: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: low

6. 幂等写入约定(与数仓域对齐) ​

  • 分区表优先:INSERT OVERWRITE 该 dt,或动态分区覆盖
  • 有主键合并语义的表:按键 upsert,避免追加造成翻倍
  • 重跑前确认:不会追加重复行(见 幂等回刷)

常见坑(至少牢记这些) ​

  1. 只重跑最下游
    ADS 修好了,DWD 仍错,下周对账又炸。必须从变更发生层起级联。

  2. 补数与日常双写同一分区
    结果非左非右。先锁分区或停日常实例。

  3. 大窗一口吃完
    30 天并行打满 YARN/K8s,今日 SLA 全军覆没。限流 + 保 P0 窗口。

  4. 口径变更不改字典、不标修订
    业务对比历史曲线「突然跳变」却无说明。补数单同步口径版本与对外公告。

  5. 追数打乱时间顺序且下游有状态依赖
    某些累计指标依赖「按日顺序」。无状态依赖则严格按 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 原创调度/回刷实践,已改写成可执行清单;未包含未公开公司工单系统与集群名。