一、离线架构的基石:传统ETL流程、数据仓库分层与调度痛点

聊数据架构,绕不开离线。哪怕现在实时计算再火,离线这套东西依然是绝大多数公司的数据底座。我入行那会儿,每天最熟悉的就是凌晨跑批的日志,看着调度系统里一串串绿色勾号亮起来,才算一天结束。

这一章,咱们把离线架构的老底翻一翻。ETL怎么流转、分层怎么设计、调度为什么让人头疼——这些看似基础的东西,恰恰是后面理解实时复用的前提。

1.1 传统ETL:数据从源头到仓库的第一公里

ETL,全称 Extract-Transform-Load。说白了就是三步:从源系统把数据拽出来,洗一洗,再塞进目标库。听起来简单,但坑都在细节里。

核心流程拆解

  • Extract(抽取):从业务库(MySQL、Oracle)、日志文件、API接口拉取原始数据。我见过最粗暴的做法是直接全表SELECT *,生产库差点被拖垮。后来大家学乖了,用增量抽取——按时间戳或自增ID分批拉。
  • Transform(转换):清洗脏数据、字段映射、类型转换、业务逻辑计算。这一步最耗时间,也最容易出幺蛾子。比如日期格式不统一、空值处理策略不一致,都是老生常谈的问题。
  • Load(加载):把处理好的数据写入目标表。常见策略有全量覆盖、增量追加、拉链表更新。

我曾经接手过一个项目,ETL脚本全是存储过程,几千行SQL揉在一起。改一个字段映射,得翻半天代码,还不敢保证没漏掉关联逻辑。后来我强制团队把ETL拆成三个独立阶段,每个阶段只做一件事,调试效率翻了一倍。

个人习惯:ETL脚本里,我坚持在每个步骤前后加校验——行数校验、主键唯一性校验、关键字段空值率校验。宁可多跑5分钟,也不让脏数据流到下一层。

1.2 数据仓库分层:ODS → DWD → DWS → ADS

分层不是拍脑袋想出来的。早期数仓就是一张大宽表,业务一多,表结构乱成一锅粥。后来大家发现,把数据按处理深度分层管理,能大幅降低耦合度。

我习惯把分层理解成「加工流水线」:

分层 全称 核心职责 典型存储粒度
ODS 操作数据存储 原封不动保留源系统数据,只做简单格式统一 全量/增量原始记录
DWD 数据明细层 清洗、去重、维度退化、事实表标准化 明细粒度事实 + 维度
DWS 数据服务层 按主题做轻度汇总(日/周/月聚合) 汇总宽表、指标中间表
ADS 应用数据层 面向具体业务报表、大屏、即席查询 高度聚合、预计算

举个例子你就明白了。假设电商订单数据:

  • ODS:直接把订单表、支付表、物流表从MySQL同步过来,字段名、类型都不改。
  • DWD:把三张表关联成一张订单明细宽表,统一用户ID格式,过滤掉测试订单。
  • DWS:按天统计每个品类的订单数、GMV、退款率。
  • ADS:输出给BI系统的「每日销售战报」数据集。

避坑指南:我曾经见过一个团队,ODS层直接暴露给业务查询,结果源系统表结构一变更,下游报表全崩。记住——ODS只做存储,不做服务。任何业务查询都应该走DWS或ADS。

分层的好处很明显:每一层只依赖上一层,改一层不影响其他层。比如源系统字段改名,你只需要改ODS到DWD的映射脚本,DWS和ADS完全不用动。

1.3 离线调度:看似简单,实则处处是坑

离线调度,说白了就是「定时跑批」。但真正做过的人都知道,这玩意儿远没有想象中省心。

我整理了几个最常见的痛点:

  1. 依赖关系混乱:A任务跑完才能跑B,B跑完才能跑C。但实际中经常出现循环依赖、漏配依赖、跨层级依赖写死的情况。有一次凌晨2点,DWS层任务跑完了,但ODS层有个分区还没到位,整条链路卡死。
  2. 数据延迟不可控:源系统数据凌晨1点才到位,ETL脚本跑2小时,DWD再跑1小时……等ADS层出数,已经早上7点了。业务方8点要看报表,中间一点缓冲都没有。
  3. 重跑机制脆弱:某天ETL脚本报错,修复后需要重跑。但下游任务已经基于错误数据跑完了,你得手动清空下游数据再触发重跑。稍有不慎,数据就出现「断层」或「重复」。
  4. 资源争抢严重:所有任务集中在凌晨跑,集群资源打满,慢任务拖死快任务。我遇到过Hive任务因为内存不足被YARN kill,排查了半天才发现是另一个团队的大查询抢了资源。

我的经验:调度系统里,我坚持两条铁律——① 每个任务必须设置超时阈值和重试次数;② 关键路径上的任务(比如ODS到DWD的清洗任务)单独分配资源池,避免被非关键任务挤占。

下面这张图,是我对离线架构核心逻辑的总结。你可以看到数据从源端到应用层的完整流向,以及调度系统在其中扮演的「指挥官」角色。

离线数据架构核心流程图 离线数据架构核心流程 业务数据源 日志/埋点 外部接口 ODS 层 原始数据存储 增量/全量同步 格式统一 分区保留 DWD 层 数据清洗 维度退化 事实表标准化 去重/过滤 DWS 层 轻度汇总/宽表 ADS 层 报表/大屏/即席 调度系统 依赖管理 任务编排 重试/告警 资源分配 血缘追踪 说明 • 数据从左到右流动 • 调度系统控制全流程 • 每层只依赖上一层

你看,离线架构的每一层都有明确职责,调度系统则负责把这些环节串起来。但问题也出在这里——调度是「定时触发」而非「事件驱动」。一旦某个环节延迟,整条链路就得等。这也是为什么后来大家开始琢磨实时架构——不是离线不好,而是有些场景它确实扛不住。

一句话总结:离线架构的核心是「分层解耦 + 定时调度」。它稳定、成熟、适合批量处理,但面对秒级延迟需求时,力不从心。理解这些痛点,你才能明白后面实时复用方案的价值所在。