一、离线与实时流水线概述:数据架构演进、Lambda 架构与 Kappa 架构对比、离线与实时场景定义
大家好,我是这次课程的主讲。做了十几年数据架构,我见过太多团队在「离线」和「实时」之间反复横跳。说白了,这两者不是非此即彼的选择题,而是一道需要你理解本质的融合题。
这一章,我们先打好地基。我会从数据架构的演进讲起,对比 Lambda 和 Kappa 这两种主流思路,再帮你理清离线与实时到底各自解决什么问题。嗯,这里面的坑,我踩过不少,咱们慢慢聊。
数据架构的演进:从 T+1 到秒级响应
最早的数据架构,其实很简单。每天凌晨跑批,把业务库的数据抽到数仓,第二天出报表。这就是经典的 T+1 模式。我 2012 年刚入行时,做的就是这个。
但业务发展太快了。老板要实时大屏,运营要看分钟级转化,风控要毫秒级拦截。传统离线架构根本扛不住。于是,架构开始分层、分流、分场景。
核心演进脉络:
- 单体数仓时代:所有数据集中存储,ETL 按天调度。简单,但慢。
- 离线分层时代:ODS、DWD、DWS、ADS 分层建设,复用性提升。但仍然是 T+1。
- 离线 + 实时混合时代:离线层做全量计算,实时层做增量计算。Lambda 架构诞生。
- 流批一体时代:用同一套引擎、同一套代码处理离线和实时。Kappa 架构兴起。
你想想看,从「跑批」到「流式」,本质上是数据时效性需求的倒逼。我个人习惯把这种演进看作「数据管道从水管变成了高速公路」——水管只能单向慢流,高速公路可以多车道、高并发、实时调度。
Lambda 架构 vs Kappa 架构:一场关于「复杂度」的博弈
说到离线与实时的融合,绕不开这两个架构。我直接给你画张对比图,一目了然。
先看一张架构对比图:
这张图我画得很清楚。Lambda 架构把数据拆成两条路:一条走离线批处理,一条走实时流处理,最后在服务层合并。Kappa 架构则只有一条路——全量数据都走流处理,需要历史数据时,从 Kafka 重放即可。
Lambda 架构:成熟但沉重
Lambda 架构是 Nathan Marz 提出的。它的核心思想是「用离线层保证准确性,用实时层保证低延迟」。听起来很完美,对吧?
但我在项目中遇到过一个问题:两套代码,两套引擎,同样的逻辑要写两遍。比如一个简单的 UV 计算,离线用 Hive SQL,实时用 Flink SQL,结果经常对不上。为什么?因为窗口语义、去重逻辑、数据到达顺序都不一样。你想想看,排查这种数据差异有多痛苦。
我曾经踩过的坑:有一次做用户画像标签,离线层和实时层算出来的「活跃用户」差了 15%。查了两天,发现是离线层用了自然日窗口,实时层用了滑动窗口。从那以后,我要求团队必须把窗口定义统一写在架构文档里,两边的代码都要引用同一份配置。
Kappa 架构:简洁但有前提
Kappa 架构是 Jay Kreps 提出的。它的核心思想是「既然流处理引擎已经足够强,为什么还要维护两套?」说白了,就是用一套流引擎处理所有数据。
Kappa 架构的关键在于「数据重放」。你需要把原始数据全部存在 Kafka 里,当需要重新计算历史数据时,从最早的 offset 开始重放。嗯,这里要注意——Kafka 的存储成本不低,而且重放速度受限于消费能力。
| 对比维度 | Lambda 架构 | Kappa 架构 |
|---|---|---|
| 代码维护 | 两套代码(批 + 流),逻辑需对齐 | 一套代码,流批一体 |
| 引擎依赖 | 批引擎(Spark/Hive)+ 流引擎(Flink) | 单一流引擎(Flink/Kafka Streams) |
| 数据一致性 | 离线层和实时层可能不一致,需合并服务层兜底 | 天然一致,因为只有一条处理链路 |
| 历史重算 | 离线层直接重跑全量数据 | 从 Kafka 重放原始数据 |
| 存储成本 | 较低,离线层用 HDFS,实时层用 KV 存储 | 较高,Kafka 需要保留全量历史 |
| 适用场景 | 对准确性要求极高,且实时和离线逻辑差异大 | 实时性要求高,且历史重算频率低 |
我个人习惯这样选型:如果团队规模大、业务逻辑复杂、对数据准确性零容忍,Lambda 架构更稳妥。如果团队精干、技术栈统一、业务以实时为主,Kappa 架构更清爽。
离线与实时场景定义:什么时候该用谁?
很多新手会问:「离线是不是过时了?」当然不是。离线有离线的优势,实时有实时的边界。我帮你梳理一下典型场景。
离线场景:全量、准确、可回溯
- 财务对账:一分钱都不能错,T+1 完全可接受。
- 月度/年度报表:需要全量数据聚合,离线批处理更稳定。
- 历史数据回溯:比如分析过去三年的用户行为,离线跑一次就行。
- 模型训练:机器学习模型需要全量特征工程,离线更高效。
实时场景:增量、低延迟、事件驱动
- 实时大屏:秒级刷新,展示当前业务状态。
- 风控拦截:毫秒级判断,阻止欺诈交易。
- 实时推荐:用户刚点击了一个商品,立刻推荐相关商品。
- 监控告警:系统指标异常时,第一时间通知运维。
我的经验之谈:不要试图把所有场景都做成实时。实时是有成本的——计算资源、存储资源、运维复杂度都会上升。我建议你遵循「80/20 原则」:80% 的查询走离线,20% 的核心场景走实时。先把离线做好,再逐步把高价值场景迁移到实时。
离线与实时融合的核心挑战
把离线和实时融合在一起,不是简单的「加一条流」就完事了。我总结了几大挑战:
- 数据一致性:同一份数据,离线算一次,实时算一次,结果不一样怎么办?
- 窗口对齐:离线用自然天,实时用滚动窗口,边界怎么统一?
- 存储选型:离线用 HDFS/Parquet,实时用 Kafka/Redis,数据怎么打通?
- 运维复杂度:两套集群、两套调度、两套监控,出了问题怎么排查?
嗯,这些问题没有标准答案。但别担心,后面的章节我会逐一拆解,给出具体的解决方案和代码示例。