订阅更新

数仓分层ODS/DWD/DWS的调度怎么编排——分层调度设计

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

本文目录
  1. 先说结论
  2. 分层DAG设计
  3. 每层的调度策略差异
  4. 实战经验:某短视频平台的分层调度
  5. 面试高频追问
  6. 总结

先说结论

分层调度的核心原则:每层独立DAG+层间依赖+分层SLA。ODS一个DAG(凌晨1:00定时触发)、DWD一个DAG(依赖ODS完成)、DWS一个DAG(依赖DWD完成)、ADS按业务域拆多个DAG(依赖DWS)。每层有独立的SLA——ODS最晚1:30、DWD最晚2:30、DWS最晚3:30、ADS最晚4:30。

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

详细讲解

数仓分层(ODS/DWD/DWS/ADS)不只是建模问题也是调度问题——每一层的任务都要在正确的时间以正确的顺序执行。在某短视频平台,100+个ETL任务按分层编排成3个DAG,每层的调度策略不同:ODS层重数据就绪、DWD层重数据质量、DWS层重时效性、ADS层重可用性。分层调度设计是大数据面试的综合题——考调度+数仓+工程三方面能力。

分层DAG设计

层DAG触发方式SLA任务数重点
ODSdag_ods_daily定时1:00+Sensor1:3020数据就绪
DWDdag_dwd_daily依赖ODS完成2:3040数据质量
DWSdag_dws_daily依赖DWD完成3:3030计算效率
ADSdag_ads_*(按业务域)依赖DWS完成4:3020+产出可用
# 分层DAG的依赖编排
 
# DAG 1: ODS层
with DAG('dag_ods_daily', schedule='0 1 * * *') as ods_dag:
    sensors = [S3KeySensor(task_id=f'wait_{t}', ...) for t in ods_tables]
    loaders = [SparkSubmitOperator(task_id=f'ods_{t}', ...) for t in ods_tables]
    for s, l in zip(sensors, loaders): s >> l
    # 每张表:先等数据到达再加载
 
# DAG 2: DWD层
with DAG('dag_dwd_daily', schedule=None) as dwd_dag:  # 不定时,依赖触发
    wait_ods = ExternalTaskSensor(
        task_id='wait_ods_complete',
        external_dag_id='dag_ods_daily',
        external_task_id='ods_final_check',
        mode='reschedule', timeout=3600)
    dwd_tasks = [SparkSubmitOperator(task_id=f'dwd_{t}', ...) for t in dwd_tables]
    checks = [PythonOperator(task_id=f'check_{t}', ...) for t in dwd_tables]
    wait_ods >> dwd_tasks >> checks

每层的调度策略差异

ODS层——重数据就绪:核心关注'数据到了没有'。每个数据源用Sensor等待,到了就加载。Sensor设超时+soft_fail——数据源延迟不阻塞其他数据源。ODS加载必须是INSERT OVERWRITE保证幂等。

DWD层——重数据质量:核心关注'数据对不对'。每个DWD表加载后跑数据质量检查(null率、行数、值域)。检查不通过告警但不阻塞下游——DWS用的是DWD的上一个成功版本。

DWS层——重时效性:核心关注'快不快'。DWS通常是最重的计算(多表JOIN+聚合),是关键路径的主要组成。优化DWS的Spark作业比优化其他层收益更大。DWS之间的依赖要精确——dws_revenue只依赖它实际用到的dwd表不要依赖所有dwd。

ADS层——重可用性:核心关注'下游能不能用'。ADS产出后推送到BI系统/API缓存/导出文件。ADS任务失败需要立即告警——因为直接影响终端用户看到的数据。

实战经验:某短视频平台的分层调度

100+任务按分层编排:ODS 20任务(并行加载20张源表)、DWD 40任务(清洗+质量检查)、DWS 30任务(聚合)、ADS 15任务(报表产出+推送)。

时间线:1:00 ODS开始 → 1:20 ODS完成 → 1:25 DWD开始 → 2:30 DWD完成 → 2:35 DWS开始 → 3:30 DWS完成 → 3:35 ADS开始 → 4:00 ADS完成。总计3小时,SLA 4:30有30分钟缓冲。

关键设计:DWD和DWS之间不是等所有DWD完成才开始DWS——而是每个DWS表只等它依赖的DWD表完成就开始。这样DWS不用等最慢的DWD表,整体时间缩短了约30分钟。

面试高频追问

追问一:为什么不把所有层放在一个DAG里?

三个原因:① 一个DAG太大难以维护(100+Task的DAG图看不清);② 不同层的触发方式不同(ODS定时、DWD依赖触发);③ 不同层的故障域要隔离——ODS层的问题不应该直接导致ADS层的DAG状态异常。分层DAG让每层可以独立重跑、独立监控、独立排查。

追问二:DWD质量检查不通过怎么办?

不阻塞下游但发告警。DWS会使用DWD的最新成功分区(可能是今天的也可能是昨天的)。告警后值班人排查DWD问题——修复后手动重跑DWD当天分区,DWS在下一次调度或手动触发后更新。这个策略的核心是'宁可用旧数据也不让报表空白'。

追问三:DataWorks的分层调度和Airflow有什么区别?

DataWorks的节点依赖是在Web UI上拖线设置,比Airflow的代码定义更直观。DataWorks还支持'基线'概念——给每层设基线时间,超过基线自动告警并追踪延迟原因。相当于内置了SLA监控。Airflow需要自己配sla_miss_callback实现类似功能。

总结

分层调度讲三层:① 架构设计(每层独立DAG+层间依赖+分层SLA,不要一个巨大DAG);② 每层策略差异(ODS重就绪、DWD重质量、DWS重时效、ADS重可用);③ 精确依赖(DWS只等它用到的DWD不要等所有DWD,缩短关键路径)。能讲出100+任务的分层时间线和精确依赖缩短30分钟的优化,面试官觉得你对数仓调度有系统设计能力。

下一篇聊任务间数据传递:XCom传了个10GB DataFrame怎么办?

你们数仓调度按层编排吗?评论区聊聊~

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

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