订阅更新

离线作业300+,凌晨3点告警把我叫醒——任务调度怎么治理?

数仓项目手册 第 13 题 约 8 分钟读完

本文目录
  1. 先说结论
  2. DAG依赖设计:强依赖 vs 弱依赖
  3. 作业分级:P0/P1/P2
  4. 幂等设计:重跑不出错
  5. 面试高频追问
  6. 实战踩坑
  7. 总结

先说结论

调度治理的核心是三件事:① 理清DAG依赖关系(该依赖的要依赖,不该依赖的要解耦);② 作业分级分优先级(不是所有作业都同等重要);③ 做好幂等设计(失败重跑不会出错)。

最常见的调度问题不是'调度工具不好用',而是'DAG设计不合理'。依赖关系过深、不必要的强依赖、没有超时设置——这些才是凌晨告警的根源。

幂等设计是基本功:任何作业,不管重跑多少次,结果必须一样。INSERT OVERWRITE天然幂等,INSERT INTO不幂等——这是最容易踩的坑。

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

详细讲解

数仓做到一定规模后,调度就成了最大的运维痛点。我在某短剧出海公司,离线作业从50个涨到300+,DAG依赖越来越复杂,凌晨3点告警是家常便饭。有一次核心ROI报表因为上游一个不重要的作业失败导致级联阻塞,业务方早上8点打开报表还是空的——那次之后我们下决心做了一次调度治理。今天把治理方案和避坑经验全讲出来。

DAG依赖设计:强依赖 vs 弱依赖

调度治理的第一步是理清依赖关系。我们把依赖分成三种:

依赖类型定义失败时行为典型场景
强依赖上游必须成功才能运行阻塞等待DWD依赖ODS、DWS依赖DWD
弱依赖上游最好成功,但失败也能运行跳过继续运行ADS依赖辅助维度表
无依赖跟上游没有数据关系独立运行不相关的业务域的作业

我们治理前的最大问题是'过度依赖'——很多不必要的强依赖导致级联阻塞。比如ADS层的ROI报表强依赖了一个'内容标签维度表'的更新任务。这个维度表每周才更新一次,但被配成了每天强依赖。某天这个维度表的更新脚本有bug跑失败了,ROI报表就被阻塞了——但ROI报表根本不需要每天最新的内容标签。

// 治理前的DAG依赖(过度依赖)
ods_ad_click -> dwd_ad_click -> dws_channel_roi -> ads_roi_report
                                     ^
              dim_content_tag --------+  <- 不必要的强依赖!
                                        内容标签跟ROI没关系
 
// 治理后的DAG依赖(解耦)
ods_ad_click -> dwd_ad_click -> dws_channel_roi -> ads_roi_report
 
dim_content_tag -> dws_content_analysis -> ads_content_report  (独立链路)

作业分级:P0/P1/P2

不是所有作业都同等重要。我们把300+作业分成三级:

级别数量SLA失败处理典型作业
P0 核心~30个上午8点前完成自动重试3次+立即电话告警ROI报表、收入报表、大屏数据
P1 重要~100个上午10点前完成自动重试3次+群通知渠道分析、用户画像更新
P2 一般~170个下午2点前完成自动重试3次+邮件通知历史趋势报表、周报数据
// 作业分级配置示例
 
// P0作业配置:
// priority: HIGH
// retry_count: 3
// retry_interval: 5min
// timeout: 60min(超时即告警)
// alert_channel: 电话 + 企微群 + 短信
// SLA_deadline: 08:00
 
// P1作业配置:
// priority: MEDIUM
// retry_count: 3
// timeout: 120min
// alert_channel: 企微群
// SLA_deadline: 10:00
 
// P2作业配置:
// priority: LOW
// retry_count: 3
// timeout: 180min
// alert_channel: 邮件
// SLA_deadline: 14:00

分级的关键价值:P0作业的资源优先级最高,调度引擎优先分配资源给P0。当集群资源紧张时,P2作业可以排队等待,但P0作业必须立即运行。这避免了'一个不重要的作业占用大量资源导致核心报表超时'的问题。

幂等设计:重跑不出错

幂等是调度治理的基本功——任何作业重跑N次结果必须一样。看起来简单,但很容易踩坑:

-- 幂等写法:INSERT OVERWRITE(重跑会覆盖,结果一样)
INSERT OVERWRITE TABLE dws_channel_roi_1d PARTITION(dt='${bizdate}')
SELECT channel, country_code, SUM(pay_amount) AS revenue
FROM dwd_user_payment_di WHERE dt='${bizdate}'
GROUP BY channel, country_code;
 
-- 非幂等写法:INSERT INTO(重跑会重复插入!)
INSERT INTO TABLE dws_channel_roi_1d PARTITION(dt='${bizdate}')
SELECT channel, country_code, SUM(pay_amount) AS revenue
FROM dwd_user_payment_di WHERE dt='${bizdate}'
GROUP BY channel, country_code;
-- 重跑一次:数据翻倍!重跑两次:数据翻三倍!
 
-- 如果必须用INSERT INTO,先DELETE再INSERT
-- 在Hive中用INSERT OVERWRITE + 分区来实现
-- 在Doris/Hologres中先DELETE WHERE dt=xxx再INSERT

面试高频追问

追问一:你们用什么调度工具?为什么选它?

我们在短剧出海公司用的是DataWorks(阿里云自带),在出海硬件品牌用的是Airflow。选择标准:如果全套阿里云技术栈(MaxCompute/Hologres),DataWorks是最省事的——跟阿里云服务原生集成,不需要自己搭建和运维。如果是开源技术栈(Spark/Hive on AWS),Airflow是社区最活跃的选择——Python写DAG灵活度高,但需要自己运维Airflow集群。DolphinScheduler也是好选择,国内社区活跃,适合中大型团队,但学习曲线比Airflow陡。

追问二:上游任务失败了,下游自动重跑时怎么保证数据正确?

靠幂等+依赖检查。上游成功重跑后,调度工具会检测到上游状态变成'成功',自动触发下游运行。因为下游是INSERT OVERWRITE(幂等),不管运行几次结果都一样。但有一个陷阱:如果上游重跑后数据变了(比如修了一个bug,数据量从100万变成120万),下游必须也要重跑——不能只重跑上游不重跑下游,否则下游还是基于旧数据。我们的做法是:P0链路上游重跑后,自动级联重跑所有下游。

追问三:怎么处理跨天运行的长任务?

这在大数据量场景很常见——凌晨0点开始跑,2点还没跑完,第二天的调度已经开始了。我们的策略是:① 每个作业设超时时间(P0作业60分钟,超时即告警排查);② 长任务拆分成多个子任务并行执行(比如按国家分区并行处理);③ 调度层面设置互斥锁——同一个作业不允许两个实例同时运行,后一个实例必须等前一个完成后才开始。

实战踩坑

调度治理中最痛的一次经历:某天凌晨4点,P0的ROI报表因为依赖链路太长(5层深度,ODS→DWD→DWS→中间表→ADS→推送Hologres),其中一个中间层的Spark作业因为数据倾斜跑了3个小时还没完成。等全链路跑完已经上午11点了——业务方等了3个小时。

后来我们做了两个优化:① 缩短关键链路深度——把5层压缩到3层,去掉了不必要的中间表(直接在DWS里做了之前中间表的逻辑);② 给每一层设置超时阈值——如果DWD在凌晨2点前没完成,跳过DWS的常规链路,直接用昨天DWS的数据+今天的增量做快速合并出ADS,保证8点前有数据(虽然可能不是最精确的)。

// 关键链路优化:降低DAG深度
 
// 治理前(5层,端到端3-4小时)
ODS -> DWD -> DWS -> tmp_roi_detail -> ADS -> Hologres推送
     30min  40min  60min(倾斜!)  20min  10min
 
// 治理后(3层,端到端1.5小时)
ODS -> DWD -> DWS(含原tmp逻辑) -> ADS+推送
     30min  50min              20min
 
// 降级方案(保底)
如果DWS在02:00前未完成:
-> 触发降级任务
-> 用昨天DWS + 今天增量ODS快速合并出ADS
-> 数据可能有1-2%误差,但保证08:00前有数据

总结

调度治理的三板斧:理清DAG依赖(解耦不必要的强依赖)、作业分级(P0/P1/P2差异化SLA)、幂等设计(INSERT OVERWRITE天然幂等)。面试时讲调度,不要只说'我们用Airflow/DataWorks'——要能说出你管理多少个作业、怎么分级、遇到过什么调度事故以及怎么优化的。调度治理不是技术难题,是工程管理能力的体现。

调度管好了,但数据质量出问题才是最致命的——下游报表全错了。下一篇聊数据质量监控体系怎么建,包括质量规则、告警机制和数据血缘。

你们有多少离线任务?凌晨被告警叫醒过吗?最长的任务跑多久?评论区聊聊~

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

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