凌晨3点ETL失败了早上才发现——失败告警和自动重试
先说结论
失败处理有三道防线:① 自动重试(处理80%的临时故障——网络抖动、连接超时、资源暂时不足);② 实时告警(重试也失败了立刻通知人工介入);③ 值班机制(明确谁负责响应、SLA是多少、升级路径是什么)。三道防线缺一不可。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
ETL作业90%的运维时间花在处理失败上。在某短视频平台用Airflow管理100+个ETL时,平均每天有3-5个任务失败——网络抖动、数据源超时、集群资源不足、SQL语法问题……没有告警系统时经常是早上运营发现报表没更新才知道ETL挂了。搭建了完整的重试+告警机制后,80%的临时故障自动恢复,剩下的20%在失败后5分钟内通知到值班人。
第一道防线:自动重试
# Airflow的重试配置
default_args = {
'retries': 3, # 最多重试3次
'retry_delay': timedelta(minutes=5), # 每次重试间隔5分钟
'retry_exponential_backoff': True, # 指数退避
# 第1次5分钟后重试,第2次10分钟,第3次20分钟
'max_retry_delay': timedelta(minutes=30), # 最大间隔30分钟
}
# 不同任务类型的重试策略
# 网络IO任务(调API/读数据库):retries=5,间隔5分钟
# 计算任务(Spark SQL):retries=2,间隔10分钟
# 数据校验任务:retries=1,间隔1分钟
# 指数退避的好处:
# 如果是临时故障(网络抖动),等几分钟通常就恢复了
# 如果是持续故障(服务宕机),越等越久不会疯狂重试
# 避免重试风暴——100个任务同时重试打垮下游服务
| 故障类型 | 特征 | 重试有效? | 建议重试次数 |
|---|---|---|---|
| 网络超时 | 偶发、短暂 | 非常有效 | 3-5次 |
| 连接池耗尽 | 高峰期出现 | 有效(等一会儿连接释放) | 3次 |
| 集群资源不足 | 资源竞争 | 可能有效 | 2-3次 |
| SQL语法错误 | 确定性错误 | 无效(重试100次也一样) | 0次 |
| 数据源不存在 | 配置问题 | 无效 | 0次 |
| 上游数据未到 | 时序问题 | 可能有效(等上游完成) | 3-5次 |
核心原则:可重试的故障(临时性的)配重试,不可重试的故障(确定性的)不配重试或只配1次。区分方法:如果失败原因每次都一样,就是确定性错误不需要重试。如果失败是偶发的,就是临时故障需要重试。
第二道防线:实时告警
# Airflow的告警回调配置
def alert_on_failure(context):
task = context['task_instance']
dag_id = context['dag'].dag_id
task_id = task.task_id
execution_date = context['execution_date']
log_url = task.log_url
message = (f'ETL FAILED\n'
f'DAG: {dag_id}\n'
f'Task: {task_id}\n'
f'Time: {execution_date}\n'
f'Log: {log_url}')
send_feishu_alert(message) # 发飞书告警
default_args = {
'on_failure_callback': alert_on_failure, # 任务失败时调用
'on_retry_callback': alert_on_retry, # 重试时也通知(可选)
}
# 告警分级:
# P0(核心报表失败):飞书+电话+短信
# P1(重要ETL失败):飞书+短信
# P2(非核心任务失败):飞书群消息
第三道防线:值班机制
| 机制 | 内容 | 我的实践 |
|---|---|---|
| 值班轮转 | 每周一人值班,处理告警 | 2人轮换,用飞书机器人提醒换班 |
| SLA定义 | 核心报表必须在8点前产出 | 老板看的报表7:30 SLA,其他9:00 |
| 升级路径 | 30分钟未处理自动升级给leader | 飞书告警30分钟无人认领通知leader |
| 故障复盘 | 每次P0故障后做Root Cause分析 | 写Post-Mortem文档,避免同类问题 |
实战经验:从'早上才发现'到'5分钟内响应'
在某短视频平台,搭建完整告警体系的过程:
阶段一(裸奔期):没有告警。ETL凌晨失败了没人知道,早上运营发现报表没更新才通知数据组。平均故障发现时间:4-6小时。
阶段二(基础告警):配了on_failure_callback发飞书消息。故障发现时间降到30分钟(有人看手机的话)。但凌晨告警经常被睡着的人错过。
阶段三(完善体系):① 自动重试处理80%临时故障;② P0告警加电话(飞书机器人转电话)确保凌晨能叫醒人;③ SLA告警——如果核心报表7:30还没产出,直接电话通知值班人;④ 故障自愈——常见的失败模式(如连接池耗尽)写自动修复脚本。
效果:故障自动恢复率80%(重试搞定),人工介入的故障平均响应时间5分钟,核心报表SLA达标率从85%提升到99.5%。
面试高频追问
追问一:重试会不会导致数据重复?
会!如果ETL写了一半失败然后重试,已经写入的数据不会自动回滚。重试后会再写一遍——数据就重复了。这就是为什么ETL必须设计成幂等的(第5篇详讲)。INSERT OVERWRITE是幂等的(覆盖重写),INSERT INTO不是(追加)。
追问二:告警太多怎么办(告警疲劳)?
三个方法:① 告警降噪——同一个任务1小时内只告警一次,不要每次重试都告;② 告警分级——P2任务的告警只发群消息不打电话,避免非核心告警干扰;③ 自动恢复——能自动修复的故障不告警(比如连接池耗尽自动重启连接)。我在某短视频平台把日均告警从50+条降到了10条以内。
追问三:SLA怎么设?
从业务需求反推。老板每天早上8点看报表——报表任务SLA是7:30。报表依赖的DWS层SLA是7:00。DWS依赖的DWD层SLA是5:00。ODS层SLA是3:00。每层预留1-2小时缓冲。如果某一层经常卡SLA,就需要优化那一层的任务性能或调整调度时间。
总结
失败处理面试讲三道防线:① 自动重试(指数退避、区分可重试和不可重试故障、处理80%临时问题);② 实时告警(on_failure_callback、分级告警P0电话P1短信P2群消息);③ 值班机制(轮转值班、SLA定义、升级路径、故障复盘)。能讲出从'早上才发现'到'5分钟响应'的完整建设过程和SLA达标率从85%到99.5%的效果,面试官会觉得你有完整的调度运维体系思维。
下一篇聊幂等性设计:重跑一次数据翻倍了——ETL怎么设计才能安全重跑?
你们ETL的告警体系完善吗?用什么告警方式?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长