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 架构 纯流处理 流批一体 一套代码,两种模式 痛点 两套代码维护 数据口径不一致 痛点 历史重放性能瓶颈 复杂 ETL 实现困难 目标 资源复用 降本增效 演进逻辑 1. Lambda 解决了“既要实时又要准确”的问题,但引入了代码维护成本。 2. Kappa 用纯流处理简化了架构,但牺牲了历史重算的性能。 3. 流批一体在 API 层面统一,引擎层面自动优化,兼顾了性能和一致性。 4. 核心变化:从“架构妥协”走向“架构统一”。

从这张图你可以看到,流批一体不是凭空冒出来的。它是在 Lambda 和 Kappa 的基础上,取长补短的结果。我个人认为,未来 3-5 年,流批一体将成为大数据架构的主流。原因很简单:它能帮企业省钱,省人,省时间。

选型建议:如果你正在设计一个新系统,我建议直接上流批一体。如果是在改造老系统,可以从 Lambda 架构中,把那些“批处理和流处理逻辑完全一致”的作业,先迁移过来。一口吃不成胖子,但可以先挑软柿子捏。