Lambda 与 Kappa:两代架构的抉择
聊流批一体,绕不开两个名字:Lambda 和 Kappa。这两个架构,我入行那会儿可是天天挂在嘴边。说白了,它们代表了两种完全不同的设计哲学。一个求稳,一个求简。今天咱们就掰开揉碎了看看,它们到底差在哪,以及为什么现在大家都在往流批一体上靠。
Lambda 架构:曾经的“银弹”,如今的“包袱”
Lambda 架构,我记得是 2011 年左右火起来的。那时候大数据刚起步,大家发现批处理(比如 Hive)算得准但太慢,流处理(比如 Storm)快但结果总有点偏差。怎么办?Nathan Marz 一拍脑袋:两条路都走,最后合并结果不就行了?
这就是 Lambda 的核心思想:
- 批处理层(Batch Layer):全量数据,算得准,但延迟高(小时级)。
- 流处理层(Speed Layer):实时数据,算得快,但精度低(秒级)。
- 服务层(Serving Layer):把两边的结果合并,对外提供服务。
听起来挺完美对吧?我在 2015 年参与过一个电商大促项目,当时就用的这套。结果呢?嗯,踩了不少坑。
Lambda 架构的核心痛点
- 维护两套代码:批处理用 Hive SQL,流处理用 Storm 的 Java API。同样的业务逻辑,你得写两遍。改一个字段,两边都得改,漏一个就等着数据对不上吧。
- 数据口径不一致:这是最要命的。批处理跑的是 T-1 的全量数据,流处理跑的是当天的增量。两边的聚合逻辑稍微有点差异,出来的结果就对不上。我记得有一次,批处理算出的 GMV 比流处理多了 0.5%,业务方追着我们问了三天。最后发现是批处理里一个去重逻辑写错了,但流处理里没这个逻辑。
- 运维成本高:两套集群,两套监控,两套告警。出问题你得先判断是批处理挂了还是流处理挂了,还是合并层挂了。
我的经验:如果你现在还在用 Lambda,我建议你仔细看看批处理和流处理里,有没有重复的 ETL 逻辑。我曾经在一个项目里发现,同样的数据清洗,批处理里写了一遍,流处理里又写了一遍,而且写法还不一样。这种地方,就是流批一体的切入点。
Kappa 架构:一条道走到黑
Kappa 架构,是 Jay Kreps(Kafka 的作者)在 2014 年提出的。他的想法很简单:既然流处理能处理无限数据,为什么还要分两层?
Kappa 的核心思想:
- 只用一套流处理引擎:所有数据都走流处理。批处理?不存在的。你只需要把数据源当成一个无限流,然后实时计算。
- 重放机制:如果需要重新计算历史数据,就从 Kafka 等消息队列里重放数据。说白了,就是把历史数据当成“慢速的实时数据”来处理。
这个想法很优雅。但实际落地呢?我试过。2017 年,我在一个日志分析项目里尝试了纯 Kappa。结果发现,当数据量达到每天几百 TB 时,重放历史数据的时间成本高得吓人。而且,流处理引擎(当时用的 Flink)在处理超大状态时,Checkpoint 经常失败。
Kappa 架构的局限性
- 重放性能瓶颈:历史数据重放,本质上是把批处理当流处理跑。数据量一大,Kafka 的吞吐和 Flink 的状态管理都会成为瓶颈。
- Exactly-Once 语义的代价:流处理要实现精确一次,需要引入分布式快照和事务。这在大规模场景下,性能损耗不小。
- 不适合复杂 ETL:有些批处理场景(比如多表 Join、复杂窗口聚合),用流处理实现起来非常别扭,代码可读性也差。
所以,Kappa 架构虽然解决了“两套代码”的问题,但引入了新的性能问题。它更适合数据量可控、逻辑简单的场景。对于复杂的大数据 pipeline,纯 Kappa 有点力不从心。
流批一体:取长补短
Lambda 和 Kappa 都有各自的短板。那有没有一种架构,既能像 Lambda 一样处理复杂逻辑,又能像 Kappa 一样只用一套代码?
有,就是流批一体。
流批一体的核心思想:同一套 SQL/API,既能跑在流模式,也能跑在批模式。底层引擎自动优化执行计划。
说白了,你写一份代码,引擎自己决定:
- 如果数据源是实时的,就用流模式跑。
- 如果数据源是历史的,就用批模式跑。
- 甚至,可以流批混合跑。
我目前最看好的,是 Flink 的流批一体方案。Flink 在 1.12 版本之后,统一了流处理和批处理的 API。你写一个 Table 或 SQL 作业,引擎会根据数据源的特性,自动选择执行模式。
-- 同一个 SQL,既能跑流,也能跑批
SELECT
TUMBLE_START(ts, INTERVAL '1' HOUR) AS window_start,
product_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY
TUMBLE(ts, INTERVAL '1' HOUR),
product_id;
这段 SQL,如果 orders 表是 Kafka 的实时流,Flink 会启动一个流式窗口作业。如果 orders 表是 Hive 的历史分区,Flink 会启动一个批式作业,用更高效的方式处理。
流批一体的核心优势
- 一套代码:不再需要维护批处理和流处理两套逻辑。改一处,处处生效。
- 数据口径一致:同一套 SQL 语义,批处理和流处理的计算结果天然对齐。不会再出现“批处理比流处理多 0.5%”的尴尬。
- 资源复用:同一套集群,既能跑批作业,也能跑流作业。资源利用率大幅提升。
- 运维简化:一套监控,一套告警,一套部署流程。
架构选型对比
为了让你看得更清楚,我整理了一个对比表。这个表,我建议你收藏一下,做架构选型时直接拿出来用。
| 维度 | Lambda 架构 | Kappa 架构 | 流批一体架构 |
|---|---|---|---|
| 代码维护 | 两套代码(批+流) | 一套代码(纯流) | 一套代码(流批统一) |
| 数据一致性 | 容易不一致 | 天然一致 | 天然一致 |
| 历史重算 | 批处理直接重算 | 流重放,性能瓶颈 | 批模式重算,性能优 |
| 实时性 | 秒级(流层) | 秒级 | 秒级 |
| 吞吐量 | 高(批层) | 中等(受限于流引擎) | 高(批模式可优化) |
| 运维复杂度 | 高(两套集群) | 低(一套集群) | 低(一套集群) |
| 适用场景 | 历史遗留系统 | 数据量可控、逻辑简单 | 新系统建设、降本增效 |
你看,流批一体在代码维护、数据一致性、运维复杂度上,几乎是碾压级的优势。唯一的短板是,它对引擎的要求比较高。目前只有 Flink 和 Spark 3.0+ 支持得比较好。
一张图看懂架构演进
下面这张图,是我自己画的。它清晰地展示了从 Lambda 到 Kappa,再到流批一体的演进路径。你可以看到,每一代架构都在解决上一代的问题。
从这张图你可以看到,流批一体不是凭空冒出来的。它是在 Lambda 和 Kappa 的基础上,取长补短的结果。我个人认为,未来 3-5 年,流批一体将成为大数据架构的主流。原因很简单:它能帮企业省钱,省人,省时间。
选型建议:如果你正在设计一个新系统,我建议直接上流批一体。如果是在改造老系统,可以从 Lambda 架构中,把那些“批处理和流处理逻辑完全一致”的作业,先迁移过来。一口吃不成胖子,但可以先挑软柿子捏。