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_dbods 层业务数据库变更事实数据
topic_logods 层用户行为日志原始数据
topic_dwddwd 层维度模型明细数据

3.3 ZooKeeper 的作用

图中下方标注了分布式协调 ZooKeeper,它在整个架构中承担:

  • Kafka 集群的元数据管理和 Broker 协调
  • Flink 消费位点的协调(旧版 Flink 依赖 ZK,新版用 Kafka 自身管理)
  • 各组件之间的分布式锁和配置同步

为什么需要 Kafka 做缓冲?

  1. 削峰填谷:大促期间流量激增,Kafka 可以暂存数据,下游 Flink 按自身处理能力消费
  2. 解耦:数据源和消费端互不依赖,可以独立扩缩容
  3. 多消费者:同一份数据可以被 dwd、dim 等多个 Flink 任务同时消费,互不干扰
  4. 数据回溯: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)精确一次性消费、实时计算
维度层 DIMHBase + Redis全量维度存储 + 热点缓存,供 DWS 层关联
数据应用层 ADSDoris实时 OLAP 查询,前端唯一数据源
可视化SpringBoot + Sugar统一 API、大屏展示

架构的核心思想:

  • 用 Kafka 做缓冲解耦
  • 用 Flink 做实时计算引擎
  • 用数仓分层保证数据质量
  • 用 HBase + Redis 构建 DIM 维度层,供 DWS 层 Flink 任务关联维度数据
  • 用 Doris 构建 ADS 应用层,作为前端唯一数据源,所有报表和可视化都从 Doris 查询

理解这张图,就理解了实时数仓的全貌。


参考资源

更多推荐