3. 技术选型与架构:Lambda、Kappa 与流批一体
聊到增量计算,绕不开一个核心问题:架构怎么选?
我见过不少团队,一上来就追新框架,结果业务跑不起来。说白了,选架构就是选妥协。你得在实时性、准确性、开发成本和运维复杂度之间找平衡。
这一节,我把三种主流架构掰开揉碎讲清楚。再附上我对 Flink、Spark Streaming、Kafka Streams 的真实体感。
3.1 Lambda 架构:经典但沉重
Lambda 架构是 2011 年由 Nathan Marz 提出的。它的核心思路很简单:用两条路处理数据。
- 批处理层(Batch Layer):全量数据,高延迟,保证最终准确。
- 流处理层(Speed Layer):实时数据,低延迟,提供近似结果。
- 服务层(Serving Layer):合并两边的结果,对外提供服务。
我的经验:Lambda 架构最大的坑,不是技术实现,而是逻辑一致性。批处理和流处理用两套代码,同样的业务逻辑要写两遍。我曾经在一个金融项目中排查过三天,才发现批处理窗口和流处理窗口的聚合逻辑差了 5 分钟。那感觉,真是一言难尽。
注意:Lambda 架构的运维成本很高。你需要维护两套管道、两套存储、两套监控。除非你的团队足够大,否则我不建议中小团队直接上 Lambda。
3.2 Kappa 架构:简化,但有前提
Kappa 架构是 Jay Kreps 提出的。他当时觉得 Lambda 太复杂了,就问了一句:为什么不用一套流引擎搞定所有事?
Kappa 的核心思想:所有数据都走流处理。批处理只是流处理的一个特例——把历史数据重新回放一遍。
- 统一入口:所有数据进入 Kafka 等消息队列。
- 流处理引擎:实时处理新数据,也能回溯处理历史数据。
- 结果存储:输出到数据库或文件系统。
嗯,这里要注意。Kappa 架构有个硬前提:你的消息队列必须能保存全量历史数据。Kafka 可以做到,但存储成本你得算清楚。我见过一个团队,Kafka 集群的磁盘撑了三个月就爆了,最后不得不回退到 Lambda。
避坑指南:我曾经在 IoT 场景中尝试过纯 Kappa。数据量每天 10TB,Kafka 保留 7 天就撑不住了。最后我们妥协了:热数据走 Kappa,冷数据走离线批处理。你看,架构从来不是非黑即白。
3.3 流批一体架构:理想与现实
流批一体,是近几年最火的概念。它的目标很性感:一套 API,一套引擎,同时支持流和批。
Flink 是这方面的代表。它认为「批是有界流,流是无界批」。你写一套代码,引擎自动决定怎么执行。
- 统一 API:DataStream API 和 Table API 同时覆盖流和批。
- 事件时间语义:不再依赖数据到达时间,而是数据本身携带的时间戳。
- 精确一次语义:端到端的一致性保证。
说实话,流批一体在理论上是完美的。但在实际项目中,我遇到过不少问题。比如,批处理场景下的数据倾斜,在流模式下可能被放大。再比如,状态后端的管理,流和批的 checkpoint 策略完全不同。
我的建议:如果你的业务场景以实时为主,偶尔跑跑历史回溯,流批一体是很好的选择。但如果你的批处理任务很重(比如每天几百张 Hive 表),我建议还是保留专门的批处理引擎。
3.4 主流框架对比:Flink vs Spark Streaming vs Kafka Streams
选框架,我一般看三个维度:延迟、吞吐、生态。下面这张表是我个人的总结。
| 维度 | Apache Flink | Spark Streaming | Kafka Streams |
|---|---|---|---|
| 处理模型 | 真正的逐条流处理 | 微批次(Micro-batch) | 流处理(基于 Kafka 分区) |
| 延迟 | 亚秒级(毫秒) | 秒级(通常 1-5 秒) | 亚秒级(毫秒) |
| 吞吐 | 高(依赖状态后端) | 极高(批量处理优势) | 中(受限于 Kafka 分区) |
| 状态管理 | 内置状态后端(RocksDB/Heap) | 依赖外部存储(Redis/HBase) | 内置状态存储(RocksDB) |
| 精确一次 | 原生支持 | 支持(需配置) | 支持(需幂等生产者) |
| 生态集成 | 丰富(Hive/HBase/ES/Kafka) | 极丰富(Hadoop 全家桶) | 仅限 Kafka 生态 |
| 学习曲线 | 中高 | 中 | 低 |
| 适用场景 | 实时 ETL、风控、监控 | 离线批处理、准实时报表 | 轻量级流处理、Kafka 原生应用 |
3.4.1 Flink:实时计算的王者
我个人最常用 Flink。它的优势在于真正的逐条处理和强大的状态管理。你想想看,在风控场景中,每一条数据都要在毫秒级内判断是否违规。Spark Streaming 的微批次模型,天然做不到这一点。
但 Flink 也有缺点。它的 checkpoint 机制在大状态场景下很吃资源。我曾经有一个任务,状态大小到了 100GB,每次 checkpoint 都要卡好几秒。后来我们优化了状态结构,才把问题解决。
3.4.2 Spark Streaming:批处理的延伸
Spark Streaming 本质上是把流切成一个个小批次。它的优势在于生态。如果你的团队已经用了 Spark 做离线计算,那么扩展到流处理是很自然的选择。
不过,微批次模型带来的延迟问题,在某些场景下是硬伤。我记得有个用户反馈,说他们的实时大屏数据总是慢 3 分钟。查到最后,发现是 Spark Streaming 的批次间隔设成了 2 分钟,再加上处理延迟,刚好 3 分钟。换成 Flink 后,延迟降到了 500 毫秒。
3.4.3 Kafka Streams:轻量级的选择
Kafka Streams 是一个库,不是框架。它直接嵌入你的应用里,不需要单独部署集群。对于轻量级流处理场景,比如数据过滤、字段转换、简单聚合,它非常合适。
但它的局限性也很明显。第一,只能处理 Kafka 里的数据。第二,状态管理能力有限。第三,没有统一的调度和监控。如果你要做复杂的多阶段 ETL,Kafka Streams 会显得力不从心。
我的选择逻辑:
- 需要毫秒级延迟 + 复杂状态管理 → Flink
- 已有 Spark 生态 + 秒级延迟可接受 → Spark Streaming
- 轻量级任务 + 不想引入新框架 → Kafka Streams
3.5 架构选型决策树
说了这么多,到底怎么选?我画了一张图,帮你理清思路。
3.6 我的最终建议
架构选型没有银弹。Lambda 架构虽然重,但在某些需要严格数据一致性的场景下,它依然是最稳妥的选择。Kappa 架构很优雅,但前提是你搞定了 Kafka 的存储成本。流批一体是未来,但现阶段还有不少坑要填。
至于框架,我的建议是:别盲目追新。选你团队最熟悉的,选和你现有生态最匹配的。技术是为业务服务的,不是用来炫技的。
一句话总结:架构是骨架,框架是肌肉。骨架歪了,肌肉再强也跑不起来。先想清楚你要什么,再动手。