订阅更新

要回溯最近30天的数据——Backfill和历史补数

任务调度手册 第 9 题 约 6 分钟读完

本文目录
  1. 先说结论
  2. Backfill的并行度控制
  3. catchup参数——自动补数还是手动补数
  4. 实战经验:90天Backfill验证迁移结果
  5. Backfill的常见坑
  6. 面试高频追问
  7. 总结

先说结论

Backfill的核心是:幂等+参数化+并行度控制。幂等保证重跑不出错(INSERT OVERWRITE);参数化保证每天处理正确日期的数据({{ ds }});并行度控制防止Backfill把集群资源打满影响日常ETL。Airflow原生支持backfill命令,但生产环境需要额外的策略控制。

# Airflow的backfill命令
# 回溯2024年1月的数据
airflow dags backfill \
    --start-date 2024-01-01 \
    --end-date 2024-01-31 \
    --reset-dagruns \           # 清除已有的DAG Run
    daily_warehouse_etl
 
# 这个命令会为1月1日到31日各创建一个DAG Run
# 每个DAG Run的{{ ds }}分别是01-01到01-31
# Airflow按依赖关系顺序执行
 
# 注意:30天×100个Task=3000个Task实例
# 如果同时跑会把集群打满!

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

Backfill(回溯/补数)是大数据日常运维的常见操作:上游修了一个Bug需要重算最近30天的DWD;新增了一个指标需要回溯3个月的DWS;数据源变更需要重新加载全量ODS。在某知名出海硬件品牌做EMR到Databricks迁移时,迁移后需要Backfill 90天的数据验证新旧系统结果一致——90天×100+个任务=9000+次任务执行。Backfill处理不好要么把集群跑满要么数据不一致。

Backfill的并行度控制

# 方法一:限制DAG的最大活跃Run数
dag = DAG(
    'daily_warehouse_etl',
    max_active_runs=3,  # 最多同时跑3天的数据
    ...)
# 30天的backfill分成10批,每批3天并行
 
# 方法二:用Pool限制Backfill任务并发
# 创建backfill_pool,slots=20
# 日常ETL在default_pool(slots=50)
# 这样Backfill最多用20个Worker不影响日常
 
# 方法三:分批手动触发
# 先跑1-10号,验证无误后跑11-20号,再跑21-31号
# 最安全但最慢

catchup参数——自动补数还是手动补数

catchup=True(默认):DAG启动后自动补跑start_date到今天之间所有缺失的DAG Run。适合第一次部署DAG时自动回溯历史。但如果DAG的start_date设了很早(比如2020年),上线后会疯狂补跑几年的数据!

# 危险:catchup=True + 很早的start_date
dag = DAG('my_dag',
    start_date=datetime(2020, 1, 1),  # 4年前!
    schedule='@daily',
    catchup=True)  # 上线后会补跑4年的数据!
 
# 安全做法
dag = DAG('my_dag',
    start_date=datetime(2024, 1, 1),
    schedule='@daily',
    catchup=False)  # 不自动补跑,需要时手动backfill
 
# 生产建议:
# 新DAG设catchup=False
# 需要回溯时用airflow dags backfill命令控制范围和并行度
# 避免catchup=True导致的意外大规模补数

实战经验:90天Backfill验证迁移结果

在某知名出海硬件品牌从EMR迁移到Databricks后,需要Backfill 90天数据验证新系统和旧系统结果一致。

策略:① 先Backfill最近7天——快速验证核心逻辑是否正确;② 对比7天的结果(行数、聚合值、抽样校验)确认一致后Backfill 30天;③ 30天验证通过后Backfill剩余60天。分三阶段降低风险。

并行度控制:max_active_runs=5(最多5天并行),Backfill用独立的Pool(slots=30限制并发)。日常ETL不受影响。

时间线:7天Backfill用了1天,30天用了3天,60天用了5天。总共9天完成90天的Backfill+验证。

Backfill的常见坑

坑症状解决
catchup=True失控上线后补跑几年数据把集群打满catchup=False+手动backfill
非幂等任务Backfill导致数据翻倍INSERT OVERWRITE(第5篇)
日期用CURRENT_DATEBackfill所有天读的是同一天数据用{{ ds }}参数化(第5篇)
并行度太高Backfill打满集群日常ETL延迟max_active_runs+独立Pool
依赖链未考虑DWD回溯了但DWS没回溯整条链路一起Backfill

面试高频追问

追问一:Backfill和重跑(Rerun)有什么区别?

重跑是对某一天的某个Task重新执行(Task级别),Backfill是对一个日期范围的整个DAG重新执行(DAG级别)。重跑通常是修复某天的问题,Backfill通常是回溯一批历史数据。Airflow中重跑用'Clear'按钮,Backfill用命令行。

追问二:Backfill时怎么不影响日常ETL?

三个手段:① 时间错开——Backfill在日常ETL完成后再跑(白天Backfill晚上ETL);② 资源隔离——Backfill用独立Pool,不和日常ETL抢Worker;③ 并行度限制——max_active_runs控制同时跑几天。

追问三:DolphinScheduler怎么做Backfill?

DS支持'补数'功能——在Web UI上选择日期范围和并行度,DS会为每天创建一个工作流实例。比Airflow的命令行更直观。DS还支持'依赖补数'——自动检测哪些下游也需要回溯。

总结

Backfill面试讲三个关键:① 幂等+参数化是前提(OVERWRITE+{{ ds }}保证回溯不出错);② 并行度控制(max_active_runs+独立Pool不影响日常ETL);③ catchup参数(新DAG设False避免失控,需要时手动backfill)。能讲出90天Backfill验证迁移的分阶段策略和并行度控制方案,面试官觉得你有大规模Backfill的实战经验。

下一篇聊调度器迁移:从Oozie/Crontab迁移到Airflow怎么做?

你们做过大规模Backfill吗?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器