五、Flink 实时数仓架构全剖析
1. 全景总览
下面这张图是一张比较完整的 Flink 实时数仓项目架构图,覆盖了从数据采集、消息缓冲、流处理、数仓分层到数据应用的完整链路。我们先整体看一下:

整个架构可以分为四大核心层:
┌─────────────────────────────────────────────────────────────┐
│ 数据采集层 → 消息缓冲层 → 流处理层 → 数据应用层 │
│ (Source) (Kafka) (Flink) (Doris) │
└─────────────────────────────────────────────────────────────┘
每一层各司其职,下面逐一拆解。
2. 数据采集层 — 两条数据入口
图中左侧清晰地展示了两条并行的数据采集链路:
2.1 业务数据链路
Web/App 业务交互 → Nginx → SpringBoot 业务服务 → MySQL
- Nginx:负责反向代理和负载均衡,把前端请求分发到后端服务
- SpringBoot:业务逻辑层,处理用户请求并写入 MySQL
- MySQL:业务数据库,存储订单、用户、商品等核心业务数据
这是数仓的主数据源,后续通过 Maxwell 实时同步到 Kafka。
2.2 用户行为数据链路
Web/App 前端埋点 → Nginx → SpringBoot 日志服务 → logFile → Flume 采集
- 前端埋点:记录用户点击、浏览、停留等行为事件
- SpringBoot 日志服务:接收埋点请求,写入本地日志文件
- Flume:分布式日志采集工具,实时收集 logFile 中的日志数据
这是数仓的行为数据源,用于后续的用户行为分析和流量统计。
为什么分两条链路?
| 维度 | 业务数据 | 行为数据 |
|---|---|---|
| 数据特征 | 结构化、事务性强 | 半结构化、量大 |
| 存储方式 | MySQL | 日志文件 |
| 同步工具 | Maxwell(CDC) | Flume(日志采集) |
| 分析重点 | 订单、用户、商品维度 | 流量、转化、路径分析 |
两条链路在 Kafka 层汇合,统一进入数仓处理流程。
3. 消息缓冲层(Kafka)— 实时数仓的"蓄水池"
Kafka 消息缓冲层,它是整个实时数仓的核心枢纽。
3.1 数据写入 Kafka
两条采集链路的数据通过不同方式写入 Kafka:
业务数据:MySQL ──Maxwell──→ Kafka
日志数据:Flume ──────────→ Kafka
- Maxwell:基于 MySQL binlog 的 CDC 工具,实时捕获数据变更(INSERT/UPDATE/DELETE),转换成 JSON 格式写入 Kafka
- Flume:从日志文件实时采集数据,写入 Kafka
3.2 Kafka 内部的分 Topic 设计
图中显示 Kafka 内部按数仓分层设立了不同的 Topic(消费缓存):
| Topic | 对应层 | 数据内容 |
|---|---|---|
topic_db | ods 层 | 业务数据库变更事实数据 |
topic_log | ods 层 | 用户行为日志原始数据 |
topic_dwd | dwd 层 | 维度模型明细数据 |
3.3 ZooKeeper 的作用
图中下方标注了分布式协调 ZooKeeper,它在整个架构中承担:
- Kafka 集群的元数据管理和 Broker 协调
- Flink 消费位点的协调(旧版 Flink 依赖 ZK,新版用 Kafka 自身管理)
- 各组件之间的分布式锁和配置同步
为什么需要 Kafka 做缓冲?
- 削峰填谷:大促期间流量激增,Kafka 可以暂存数据,下游 Flink 按自身处理能力消费
- 解耦:数据源和消费端互不依赖,可以独立扩缩容
- 多消费者:同一份数据可以被 dwd、dim 等多个 Flink 任务同时消费,互不干扰
- 数据回溯:Kafka 保留历史消息,Flink 任务重启可以从指定位点重新消费
4. Flink 流处理层 — 精确一次性消费
这是架构的核心计算层。
4.1 三个 Flink 模块
图中清晰展示了三个并行的 Flink 处理模块,分别对应数仓的三个层:
dwd 层 Flink — 明细数据层
职责:
- 事实数据关联(多表 JOIN)
- 维度退化(将维度字段下沉到事实表,减少后续 JOIN)
- 去重过滤(处理重复数据)
数据流:
Kafka(topic_db + topic_log) → Flink → Kafka(topic_dwd)
Flink 读取 MySQL 业务数据和日志行为数据,进行关联、清洗、去重后,写入 dwd 层的 Kafka Topic,形成统一的明细事实数据。
dws 层 Flink — 汇总数据层
职责:
- 多流合并(将不同来源的数据流合并)
- 维度关联(JOIN 维度表获取完整信息)
- 聚合计算(SUM、COUNT、AVG 等窗口聚合)
数据流:
Kafka(topic_dwd) → Flink → dws 层(内存/状态)→ 下游Doris
Flink 读取 dwd 层的明细数据,结合维度信息,按时间窗口进行聚合,生成汇总指标。
dim 层 Flink — 维度数据层
职责:
- 维度数据同步(从 MySQL 实时同步维度表变更)
- 广播 JOIN(将维度表广播到所有并行子任务)
- 维度表维护
数据流:
MySQL(维度表) → Flink-CDC → Kafka(topic_dim) → Flink → 维度数据/缓存
维度数据变化频率低但查询频繁,通过 Flink-CDC 实时捕获变更,广播到所有 Flink 子任务,供 dwd 和 dws 层 JOIN 使用。
4.2 精确一次性消费(Exactly-Once)
图中顶部标注的"精确一次性消费"是 Flink 的核心特性,通过以下机制实现:
Kafka Offset Commit ←→ Flink Checkpoint ←→ 两阶段提交(2PC)
- Checkpoint:Flink 定期保存计算状态到持久化存储
- Kafka Offset:消费位点与 Checkpoint 绑定,重启后从精确位置继续
- 两阶段提交:写入外部系统(如 Kafka Sink)时,先预写再提交,保证不丢不重
为什么这很重要?
在实时数仓中,数据重复会导致指标虚高(如 GMV 翻倍),数据丢失会导致指标偏低。Exactly-Once 语义保证了计算结果的准确性,这对财务指标、业务报表至关重要。
5. DIM 维度层 — HBase + Redis 维度存储与缓存策略
DIM 维度层独立于数据应用层,专门负责管理和提供维度数据。为 Flink 计算提供维度关联支撑。
5.1 维度数据存储 → HBase
Flink → 维度数据 → HBase
- HBase:分布式列式 NoSQL 数据库,适合海量维度数据的随机读写
- 存储完整的维度表(用户维度、商品维度、地区维度等)
- 支持按 RowKey 快速查询,适合"查某个用户的所有属性"或"查某个商品的详情"
- 为什么用 HBase?
- 维度数据量大(百万~千万级)
- 查询频繁但更新少
- 需要高并发点查(毫秒级)
- 支持列族,可以灵活扩展维度字段
5.2 维度缓存 → Redis(供 DWS 层查询)
Flink DWS 层 → 异步 IO 查询 Redis 维度缓存
Redis 的作用:提供维度数据查询
DWS 层在做聚合计算时,需要关联维度数据(如用户等级、商品类目、地区信息)。为了提升性能:
- 热点维度数据缓存在 Redis 中(如高频查询的用户、商品维度)
- DWS 层通过 Async I/O 异步查询 Redis,避免阻塞主流程
- 未命中时回源到 HBase 查询,并更新缓存
DWS 层查询维度的流程:
DWS 聚合计算需要关联维度
│
├─→ Async I/O 查询 Redis
│
├─ 命中 → 直接使用(毫秒级)
│
└─ 未命中 → 查询 HBase
│
└─→ 写入 Redis 缓存
│
└─→ 返回结果
💡 设计要点:Redis 作为 HBase 的旁路缓存(Side Cache),通过 Flink 的 Async IO 机制实现非阻塞的维度关联,既保证了查询性能,又不会因缓存失效导致数据丢失。HBase 和 Redis 都属于 DIM 维度层,专门为 DWS 层的计算提供维度关联数据,不参与前端查询。
6. 数据应用层 — Doris
数据应用层是实时数仓的最顶层,直接面向业务消费场景。本架构中,数据应用层由 Apache Doris 作为唯一的数据查询入口,支撑上层的所有可视化应用。
6.1 查询报表 → Doris(前端唯一数据源)
Flink(dws层聚合结果) → Doris → 前端/Sugar 可视化
- Apache Doris:MPP 架构的实时 OLAP 引擎,支持亚秒级查询
- Flink 将 dws 层的聚合结果实时写入 Doris
- 前端应用只查 Doris,展示实时看板和报表
- Sugar 可视化大屏直接连接 Doris
为什么前端只查 Doris?
| 优势 | 说明 |
|---|---|
| 查询快 | 列存 + 向量化执行,亚秒级响应 |
| 并发高 | 支持数百并发查询,满足大屏和报表需求 |
| 数据准 | DWS 层已聚合完成,数据质量有保证 |
| 架构简单 | 前端不需要关心底层的 HBase/Redis,统一从 Doris 查询 |
6.2 可视化应用
Doris → SpringBoot 数据接口服务 → Sugar 可视化
- SpringBoot:封装统一的数据 API,屏蔽底层存储差异
- Sugar:百度开源的数据可视化工具,拖拽式生成大屏和报表
- 运营人员通过 Sugar 大屏实时查看业务指标
前端应用包含:
| 应用类型 | 说明 |
|---|---|
| 数据大屏 | 实时 GMV、UV、订单量等核心指标展示 |
| 报表系统 | 日报/周报、转化率报表、渠道分析 |
| BI 工具 | 自助分析、多维透视、趋势图表 |
💡 核心设计原则:HBase 和 Redis 属于 DIM 维度层,专门为 DWS 层的 Flink 计算提供维度关联数据;Doris 属于 ADS 应用层,是前端可视化应用的唯一数据源。两者职责清晰分离,前端应用无需关心底层的维度存储细节。
7. 数据流向总结
把整张图的数据流串起来:
业务数据 行为数据
│ │
MySQL ──Maxwell──┐ Flume ──┐
│ │
▼ ▼
┌─────────────────────────┐
│ Kafka 集群 │
│ topic_db | topic_log │
└─────────────┬───────────┘
│
┌─────────────▼───────────┐
│ dim 层 Flink │ ← Flink-CDC 同步维度表
│ 维度数据同步/广播JOIN │
└──────┬──────────────────┘
│
┌──────▼──────────────────┐
│ dwd 层 Flink │ ← 事实数据关联/去重/维度退化
└──────┬──────────────────┘
│
┌──────▼──────────────────┐
│ dws 层 Flink │ ← 多流合并/维度关联/聚合计算
└──────┬──────────────────┘
│
┌─────────────┼─────────────────────────────────┐
│ │ │
│ 需要关联维度数据 │ 聚合结果写入
│ │ │
│ │ ▼
┌─────────────────────────┐ ┌──────────────────────┐
│ DIM 维度层 │ │ ADS 数据应用层 │
│ │ │ │
│ HBase Redis │ │ Doris │
│ (维度持久化) (旁路缓存) │ │ (前端唯一数据源) │
│ │ │ │
│ │ │ ↓ │
│ │ │ 前端/Sugar 可视化 │
└─────────────────────────┘ └──────────────────────┘
关键点:
- DIM 维度层(HBase + Redis):为 DWS 层 Flink 任务提供维度关联数据
- ADS 数据应用层(Doris):前端唯一数据源,所有报表和可视化都从 Doris 查询
8. 维度存储与缓存策略详解
8.1 为什么要分层存储维度数据?
┌─────────────────────────────────────────────────────┐
│ 维度数据访问模式 │
├─────────────────────────────────────────────────────┤
│ 更新频率:低(每天/每小时变更) │
│ 查询频率:高(每条事实数据都要JOIN) │
│ 数据量:大(百万~千万级) │
│ 查询模式:点查为主(按ID查详情) │
└─────────────────────────────────────────────────────┘
这种访问模式适合分层存储:
- HBase:存全量维度数据,作为"数据底座"
- Redis:缓存热点维度数据,作为"加速层"
8.2 旁路缓存(Cache-Aside)详解
应用查询维度数据
│
├─→ 查 Redis 缓存
│
├─ 命中 → 直接返回(毫秒级)
│
└─ 未命中 → 查 HBase(秒级)
│
└─→ 写入 Redis 缓存
│
└─→ 返回结果
缓存更新策略:
- 主动更新:维度表变更时,Flink 主动更新 Redis(保证一致性)
- 被动失效:缓存过期后,下次查询再加载(最终一致性)
适用场景:
- 用户维度(用户等级变更不频繁)
- 商品维度(商品信息相对稳定)
- 地区维度(几乎不变)
8.3 异步 IO(Async I/O)详解
Flink 事实流
│
│ 数据1 ──┐
│ 数据2 ──┤ 同时发送异步查询
│ 数据3 ──┤ 到 Redis/HBase
│ 数据4 ──┘
│
│ 等待所有查询完成
│
↓ 合并结果继续处理
同步 vs 异步:
| 模式 | 吞吐量 | 延迟 | 适用场景 |
|---|---|---|---|
| 同步 | 低(阻塞等待) | 高 | 查询量小 |
| 异步 | 高(并发查询) | 低 | 查询量大 |
8.4 维度缓存的刷新机制
MySQL 维度表变更
│
▼
Flink-CDC 捕获变更
│
├─→ 更新 HBase 维度存储
│
└─→ 更新 Redis 缓存
│
└─→ 发布变更事件(通知其他服务)
关键点:
- 维度变更通过 Flink-CDC 实时捕获
- 同时更新 HBase 和 Redis,保证数据一致
- 可以发布变更事件,通知下游服务刷新本地缓存
9. 架构设计亮点
9.1 精确一次性消费贯穿全链路
从 Kafka 消费 → Flink 计算 → 写入下游存储,全链路保证 Exactly-Once,这是实时数仓数据准确性的基石。
9.2 数仓分层思想落地
ODS(Kafka原始数据)→ DWD(明细事实)→ DWS(汇总指标)→ ADS(应用数据)
虽然是实时数仓,但依然遵循传统数仓的分层规范,每层职责清晰,便于维护和排查问题。
9.3 维度数据分层存储
Redis(热点缓存)←→ HBase(全量存储)
- Redis:热点维度数据缓存,支持旁路缓存和异步 IO
- HBase:全量维度数据存储,支持高并发点查
这种分层策略兼顾了查询性能和存储成本。
9.4 Flink-CDC 替代传统 CDC 工具
图中既用了 Maxwell 做 MySQL CDC,又在 Flink 层内置了 Flink-CDC,体现了技术演进:
- Maxwell:成熟稳定,适合独立部署
- Flink-CDC:与 Flink 深度集成,支持广播 JOIN 和动态配置
10. 生产环境的注意事项
| 关注点 | 说明 |
|---|---|
| Kafka 分区数 | 与 Flink 并行度对齐,避免数据倾斜 |
| Checkpoint 间隔 | 太短影响性能,太长增加数据丢失风险,通常 30s~3min |
| 状态后端选择 | RocksDB(大状态)vs Memory(小状态) |
| Watermark 设置 | 处理乱序数据的关键,需要根据业务延迟容忍度调整 |
| 维度表广播 | 维度数据量大时注意内存占用,可配合维表缓存策略 |
| 背压监控 | Flink 背压会影响端到端延迟,需要实时监控和告警 |
| Redis 缓存命中率 | 低于 90% 时需要调整缓存策略或扩容 |
| HBase 查询延迟 | P99 超过 100ms 时需要检查 Region 分布和热点 |
11. 总结
这张 Flink 实时数仓架构图展示了一个工业级实时数据平台的完整设计:
| 层次 | 核心组件 | 核心价值 |
|---|---|---|
| 数据采集 | Maxwell + Flume | 业务数据和行为数据双链路采集 |
| 消息缓冲 | Kafka + ZooKeeper | 削峰填谷、解耦、多消费者 |
| 流处理 | Flink(dwd/dws/dim) | 精确一次性消费、实时计算 |
| 维度层 DIM | HBase + Redis | 全量维度存储 + 热点缓存,供 DWS 层关联 |
| 数据应用层 ADS | Doris | 实时 OLAP 查询,前端唯一数据源 |
| 可视化 | SpringBoot + Sugar | 统一 API、大屏展示 |
架构的核心思想:
- 用 Kafka 做缓冲解耦
- 用 Flink 做实时计算引擎
- 用数仓分层保证数据质量
- 用 HBase + Redis 构建 DIM 维度层,供 DWS 层 Flink 任务关联维度数据
- 用 Doris 构建 ADS 应用层,作为前端唯一数据源,所有报表和可视化都从 Doris 查询
理解这张图,就理解了实时数仓的全貌。
参考资源
更多推荐

所有评论(0)