订阅更新

凌晨3点ETL失败了早上才发现——失败告警和自动重试

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

本文目录
  1. 先说结论
  2. 第一道防线:自动重试
  3. 第二道防线:实时告警
  4. 第三道防线:值班机制
  5. 实战经验:从'早上才发现'到'5分钟内响应'
  6. 面试高频追问
  7. 总结

先说结论

失败处理有三道防线:① 自动重试(处理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年大数据老兵,聊技术、聊职场、聊成长

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