要回溯最近30天的数据——Backfill和历史补数
先说结论
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_DATE | Backfill所有天读的是同一天数据 | 用{{ 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年大数据老兵,聊技术、聊职场、聊成长