实时数仓分层架构:ODS、DWD、DWS、ADS 各层职责与数据流转
聊实时数仓,绕不开分层。很多刚接触实时流的同学会问:“为什么非得分这么多层?直接 Kafka 接 Flink 算完写 MySQL 不就行了?”
嗯,我早期也这么干过。结果呢?业务方要一个新指标,我得从头翻 Kafka 消息,逻辑散落在十几个 Flink 作业里,改一个字段影响一片。说白了,分层不是为了炫技,是为了让数据“好管、好用、好追溯”。
今天我就把实时数仓的四层架构——ODS、DWD、DWS、ADS,掰开揉碎讲清楚。每一层干什么、数据怎么流、有哪些坑,咱们一次聊透。
核心观点:实时数仓分层不是照搬离线,而是针对“流式处理”的特点做了取舍。ODS 保原始、DWD 做清洗、DWS 汇主题、ADS 出报表——每一层都有它存在的理由。
2.1 四层架构总览
先看一张整体图,后面咱们逐层拆解。
这张图我画了很多遍。你注意看,数据是从上往下单向流动的。每一层只依赖它的上一层,不允许跨层引用。这样做的好处是:改底层逻辑不影响上层,排查问题也能快速定位。
2.2 ODS 层:原始数据的“缓冲区”
ODS,全称 Operational Data Store。说白了,就是把业务系统的数据原封不动搬进实时数仓。
我在项目中遇到过一种情况:业务方说“昨天的订单数据不对”,结果发现是 Flink 作业里做了隐式类型转换,把字符串转数字时丢了精度。如果 ODS 层保留了原始 JSON,直接回放就能对账。所以我的习惯是——ODS 层只做“搬运”,不做任何加工。
ODS 层核心职责
- 数据缓冲:用 Kafka Topic 作为统一入口,解耦生产者和消费者。
- 保真存储:保留原始消息体,包括所有字段、时间戳、元数据。
- 多源汇聚:MySQL Binlog、业务日志、埋点数据……全部进 ODS。
- 回溯能力:Kafka 消息保留一定周期(比如 7 天),方便重跑。
我的建议:ODS 层的 Topic 命名最好带上数据源标识。比如 ods_mysql_orders、ods_log_pageview。这样下游一看就知道数据从哪来,省去查文档的时间。
ODS 层数据流转示例
-- 模拟 ODS 层 Kafka Topic 中的一条订单消息(JSON 格式)
{
"topic": "ods_mysql_orders",
"partition": 3,
"offset": 1024,
"timestamp": 1712563200000,
"value": {
"order_id": "20250408001",
"user_id": 10086,
"product_id": "P998",
"amount": 299.00,
"status": "paid",
"create_time": "2025-04-08 10:00:00"
}
}
你看,这里连 partition 和 offset 都保留了。为什么?因为万一需要精确回溯某条消息,这些信息就是“坐标”。
2.3 DWD 层:数据“洗白白”的地方
DWD,Detail Warehouse Detail。这一层是实时数仓里最累的活。
ODS 层的数据是“脏”的:可能有重复、有空值、有格式不统一、有维度信息缺失。DWD 层要做的就是——清洗、去重、标准化、补齐维度。
DWD 层核心职责
- 数据清洗:过滤无效数据、修正异常值。
- 去重:基于业务主键做幂等处理,防止重复消费。
- 维度补齐:关联维表(比如用户信息、商品信息),把 ID 变成可读的字段。
- 格式统一:时间戳统一为毫秒级,金额统一为分,枚举值统一为中文。
注意:DWD 层的去重一定要用 Flink 的 ROW_NUMBER 或 Deduplicate 函数,配合事件时间 + Watermark。我曾经见过有人用处理时间去重,结果乱序数据一来,重复记录全跑进去了。
DWD 层数据流转示例
-- 经过 DWD 层处理后的订单明细(写入 Kafka Topic: dwd_order_detail)
{
"order_id": "20250408001",
"user_id": 10086,
"user_name": "张三", -- 维度补齐
"product_id": "P998",
"product_name": "智能手表", -- 维度补齐
"amount_cents": 29900, -- 统一为分
"status": "已支付", -- 枚举转中文
"event_time": 1712563200000, -- 统一毫秒时间戳
"dwd_process_time": 1712563201000
}
你对比一下 ODS 和 DWD 的数据,差别很明显。DWD 层的数据已经“干净”了,下游可以直接用。
2.4 DWS 层:轻量汇总,宽表化
DWS,Data Warehouse Summary。这一层做的是轻度聚合。
为什么要做轻度聚合?因为实时场景下,如果每次查询都去扫 DWD 的明细数据,性能扛不住。DWS 层把相同维度的指标提前算好,形成宽表。
DWS 层核心职责
- 主题划分:按业务域组织,比如订单主题、用户主题、商品主题。
- 轻度聚合:按分钟/小时粒度预计算 PV、UV、GMV 等指标。
- 宽表设计:把多个维度的指标合并到一张表里,减少 Join。
- 窗口计算:使用 Flink 的 Tumble / Hop / Session 窗口。
经验之谈:DWS 层的聚合粒度不要搞太细。我见过有人按秒聚合,结果 Kafka Topic 分区数暴涨,下游消费不过来。一般来说,分钟级聚合是性价比最高的选择。
DWS 层数据流转示例
-- DWS 层订单主题宽表(写入 Kafka Topic: dws_order_topic)
{
"window_start": "2025-04-08 10:00:00",
"window_end": "2025-04-08 10:01:00",
"product_id": "P998",
"product_name": "智能手表",
"order_count": 15,
"gmv_cents": 448500, -- 15 * 29900
"user_count": 12,
"avg_order_amount": 29900
}
你看,这里已经算好了每分钟的订单数、GMV、用户数。ADS 层直接拿这些数据做报表,不用再算一遍。
2.5 ADS 层:面向应用,直接输出
ADS,Application Data Service。这一层是离业务最近的一层。
ADS 层的数据直接供给 BI 系统、大屏、推荐引擎、风控系统。所以它的特点是:查询快、格式灵活、接口友好。
ADS 层核心职责
- 指标计算:基于 DWS 层做二次聚合,比如同比、环比、累计值。
- 报表输出:按业务需求组织数据,比如实时大屏、日报看板。
- 接口适配:输出格式适配下游系统,比如 JSON、Protobuf、JDBC。
- 数据降维:只保留业务需要的字段,减少传输量。
一个小技巧:ADS 层的数据可以同时写入 Kafka(供实时消费)和 ClickHouse(供即席查询)。这样既满足了低延迟,又支持了复杂分析。
ADS 层数据流转示例
-- ADS 层实时大屏数据(写入 Kafka Topic: ads_realtime_dashboard)
{
"report_time": "2025-04-08 10:01:00",
"total_gmv_cents": 12500000,
"total_orders": 420,
"total_users": 380,
"top_product": {
"product_name": "智能手表",
"gmv_cents": 448500,
"order_count": 15
},
"gmv_growth_rate": 0.12 -- 同比上一小时
}
2.6 各层对比与选型建议
为了让你看得更清楚,我把四层的核心差异整理成了一张表。
| 分层 | 存储介质 | 数据粒度 | 主要操作 | 典型延迟 |
|---|---|---|---|---|
| ODS | Kafka | 原始消息 | 采集、缓冲 | 秒级 |
| DWD | Kafka | 明细事件 | 清洗、去重、维度补齐 | 秒级~分钟级 |
| DWS | Kafka / OLAP | 轻度聚合 | 窗口聚合、宽表化 | 分钟级 |
| ADS | Kafka / OLAP / Redis | 业务指标 | 二次聚合、报表输出 | 分钟级~准实时 |
从这张表你能看出:越往下游,数据粒度越粗,延迟越高,但查询性能越好。这就是分层架构的 trade-off。
2.7 避坑指南:我踩过的几个坑
聊了这么多理论,最后分享几个实战中容易踩的坑。
- ODS 层 Topic 分区数设置不合理:分区数太少,写入瓶颈;太多,下游 Join 时 shuffle 压力大。我的经验是:按数据量预估,每个分区 10MB/s 左右吞吐。
- DWD 层去重逻辑写错:我曾经用
PROCTIME()做去重,结果乱序数据导致重复。后来改成ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY event_time DESC)才解决。 - DWS 层聚合粒度太细:秒级聚合导致 Kafka 消息量暴增,下游 ClickHouse 写入跟不上。后来统一改为分钟级聚合,问题解决。
- ADS 层直接查 DWD:有人图省事,ADS 层直接读 DWD 明细做计算。结果查询延迟从 100ms 飙到 5s。记住:ADS 层只依赖 DWS,不要跨层。
最后提醒一句:分层不是越多越好。如果你的业务简单,ODS → DWS → ADS 三层就够了。DWD 层可以合并到 ODS 或 DWS 里。别为了分层而分层,适合的才是最好的。