设计实时数仓
需求
设计一个实时数仓系统,支持:
- 订单、支付等核心事件秒级入仓
- 实时看板延迟 < 1 分钟
- 实时指标与离线指标口径一致
架构设计
分层设计
| 层级 | 实时方案 | 离线方案 | 说明 |
|---|---|---|---|
| ODS | Kafka Topic(原始事件) | Hive ODS 表 | 原始数据 |
| DWD | Flink 清洗 → Kafka | Spark ETL → Hive | 明细数据 |
| DWS | Flink 窗口聚合 → Doris | Spark 聚合 → Hive | 汇总数据 |
| ADS | Doris 物化视图 | Hive ADS 表 | 应用数据 |
核心组件
Flink 实时 ETL
-- Flink SQL 实时清洗示例
CREATE TABLE order_events (
order_id STRING,
user_id STRING,
amount DECIMAL(10,2),
status STRING,
event_time TIMESTAMP(3),
WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND
) WITH (
'connector' = 'kafka',
'topic' = 'order_events',
'format' = 'json'
);
-- 实时 DWD:订单明细宽表
INSERT INTO dwd_order_detail
SELECT
o.order_id,
o.user_id,
u.user_name,
o.amount,
o.status,
o.event_time
FROM order_events o
LEFT JOIN user_dim FOR SYSTEM_TIME AS OF o.event_time AS u
ON o.user_id = u.user_id;
-- 实时 DWS:每分钟 GMV 汇总
INSERT INTO dws_gmv_1min
SELECT
TUMBLE_START(event_time, INTERVAL '1' MINUTE) AS window_start,
COUNT(DISTINCT order_id) AS order_count,
SUM(amount) AS gmv
FROM dwd_order_detail
WHERE status = 'paid'
GROUP BY TUMBLE(event_time, INTERVAL '1' MINUTE);
一致性保证
| 挑战 | 解决方案 |
|---|---|
| 实时和离线数据不一致 | 统一 DWD 层逻辑,实时用 Flink SQL,离线用同逻辑 Spark SQL |
| 乱序数据 | Flink Watermark + 允许迟到数据 |
| Exactly-Once | Flink Checkpoint + Kafka 事务 + Doris 幂等写入 |
| 维表变更 | 维表快照 + Temporal Join |
常见面试问题
Q1: 实时数仓如何保证与离线一致?
答案:
- 统一数据模型:DWD 层的字段定义和清洗逻辑保持一致
- 统一指标口径:指标平台管理口径,实时/离线引用同一定义
- 对数机制:每日离线数据出来后与实时数据做自动对比
- 以离线为准:出现差异时以离线数据修正实时数据
Q2: 如何处理数据延迟和乱序?
答案:
- Watermark:允许一定的乱序范围(如 5 秒)
- 迟到数据:配置
allowedLateness,迟到数据触发增量更新 - 回溯修正:超过允许范围的数据,走离线修正任务
相关链接
- Flink - 流处理引擎
- Apache Doris/StarRocks - 实时 OLAP
- 离线 vs 实时数仓 - 架构对比
- CDC 变更数据捕获 - 实时数据同步