2、核心架构选型:Lambda vs Kappa,消息队列与流计算引擎
这一章,我们聊聊实时流水线的骨架选型。说白了,就是决定用什么姿势把数据从源头搬到下游。
我见过不少团队,一上来就追新框架,结果架构越搞越重,运维成本直接起飞。其实选型这事,没有银弹。你得想清楚:你的业务到底要什么?
2.1 架构模式:Lambda 与 Kappa 的抉择
先看两张经典的架构图。Lambda 架构,说白了就是「批流合一」——批处理层算全量,速度层算增量,最后合并。Kappa 架构呢?只留流处理一条线,历史数据重放就用流引擎重新跑一遍。
核心区别一句话:Lambda 用两条腿走路(批+流),Kappa 只用一条腿(纯流)。
我在 2018 年帮一家电商公司搭用户画像系统,当时选了 Lambda。为什么?因为他们的离线报表需要 T+1 的全量修正,而实时推荐又要求秒级响应。两条线各干各的,互不干扰。
但 Lambda 的坑也很明显——维护两套代码,两套集群。你想想看,批处理用 Hive/Spark SQL,流处理用 Flink,逻辑稍微不一致,数据就对不齐。我后来查过好几次凌晨的告警,都是因为批流合并时的时间窗口没对齐。
Kappa 架构就清爽多了。所有数据进 Kafka,Flink 从头消费,想重算历史?重置 offset 就行。但前提是:你的消息队列能存足够久的数据,且流引擎能扛住全量重放的压力。
| 对比维度 | Lambda 架构 | Kappa 架构 |
|---|---|---|
| 代码维护 | 两套(批+流) | 一套(纯流) |
| 历史修正 | 批处理层自动修正 | 需重放消息或重跑作业 |
| 资源消耗 | 较高(双集群) | 较低(单集群) |
| 适用场景 | 对数据一致性要求极高,有离线全量需求 | 纯实时场景,可接受短时回溯 |
避坑指南:我曾经见过一个团队,为了「技术潮流」硬上 Kappa,结果业务方要求每天凌晨跑一次全量对账,流引擎重放 3 天的数据要跑 6 小时。最后不得不加回批处理层,变成了「Lambda 披着 Kappa 的皮」。选型前,一定先问清楚业务对历史修正的容忍度。
2.2 消息队列选型:Kafka vs Pulsar
消息队列是实时流水线的「主动脉」。选错了,后面所有环节都跟着遭殃。
Kafka 不用多说,生态最成熟,国内大厂基本都在用。Pulsar 是后起之秀,主打存算分离和原生分层存储。
我个人的习惯是:如果团队规模不大(10 人以下),Kafka 是最稳妥的选择。文档多、踩坑经验多、招聘也容易。但如果你要支撑百万级 topic,或者需要跨地域复制,Pulsar 的架构优势就出来了。
| 特性 | Apache Kafka | Apache Pulsar |
|---|---|---|
| 存储模型 | 分区日志(存算耦合) | 存算分离(BookKeeper + Broker) |
| Topic 扩展性 | 分区数受限于磁盘和 IO | 轻松支持百万级 topic |
| 消息保留 | 基于日志段过期 | 原生分层存储(可保留无限久) |
| 运维复杂度 | 中等(依赖 ZooKeeper) | 较高(多组件协同) |
| 数据重放 | 重置 offset | 支持按时间、position 精确回溯 |
嗯,这里要注意一个细节:Kafka 的存储是跟 broker 绑定的。你扩容分区,往往需要重新均衡数据,这个过程对线上有影响。Pulsar 的存算分离,扩容 broker 几乎无感,存储层 BookKeeper 自动做负载均衡。
但 Pulsar 的客户端生态不如 Kafka 丰富。我去年做一个 IoT 项目,需要 MQTT 协议接入,Pulsar 原生支持,Kafka 还得搭桥接层。这种场景下,Pulsar 反而更省事。
我的建议:如果团队 Kafka 经验丰富,且 topic 数在几千以内,继续用 Kafka 没问题。如果从零搭建,且预期 topic 规模会快速增长,或者需要长时间保留消息(比如 Kappa 架构),Pulsar 值得一试。
2.3 流计算引擎选型:Flink vs Spark Streaming
流计算引擎是实时流水线的「大脑」。选型时,我主要看三点:实时性、状态管理、生态兼容。
Flink 是真正的逐条处理,事件时间语义原生支持。Spark Streaming 本质上是微批次,虽然 Spark 3.0 之后引入了结构化流,但底层还是微批次那一套。
为什么会这样?因为 Spark 的设计哲学是「批处理扩展出流」,而 Flink 是「流处理扩展出批」。出发点不同,导致行为差异。
我在一个金融风控项目里做过对比:同样的去重逻辑,Flink 的端到端延迟在 200ms 以内,Spark Streaming 在 2-5 秒。对于风控来说,5 秒的延迟意味着交易已经完成了,拦截就失去了意义。
| 对比维度 | Apache Flink | Spark Streaming |
|---|---|---|
| 处理模型 | 逐条处理(真流) | 微批次(伪流) |
| 延迟 | 毫秒级 | 秒级 |
| 状态管理 | 原生强状态(ValueState, MapState) | 依赖外部存储或 updateStateByKey |
| 事件时间 | 原生支持,watermark 机制成熟 | 支持但精度受批次间隔影响 |
| SQL 支持 | Flink SQL 持续演进 | Spark SQL 生态更成熟 |
| 与批处理统一 | 流批一体(同一 API) | 流批分离(不同 API) |
但 Spark Streaming 也有它的优势。如果你的团队已经重度使用 Spark 做离线,且实时性要求不高(比如分钟级报表),那 Spark Streaming 可以复用已有的 ETL 逻辑和运维体系,学习成本低很多。
一句话总结:要毫秒级延迟、复杂事件处理、强状态管理 → 选 Flink。要秒级延迟、与现有 Spark 生态集成、团队 Spark 经验丰富 → 选 Spark Streaming。
2.4 架构选型全景图
下面这张图,是我自己总结的选型决策流程。每次做新项目,我都会拿出来过一遍。
你看,整个决策链条是自上而下的。先确定业务对实时性的要求,再选架构模式,然后消息队列和计算引擎要匹配。比如你选了 Kappa 架构,那消息队列最好支持长时间数据保留(Pulsar 或 Kafka 调大保留时间),流引擎要能稳定重放(Flink 的 checkpoint 机制更可靠)。
个人经验:我一般会先画一个这样的决策树,跟业务方和开发团队一起过一遍。很多时候,讨论过程中就能发现隐藏的坑。比如业务说「要实时」,但追问下去,其实 5 秒延迟也能接受。这时候 Spark Streaming 就够用了,没必要上 Flink 增加复杂度。