1. 流批一体概述:流式计算与批处理的概念、Lambda架构的痛点、Kappa架构的演进、流批一体的核心价值
1.1 流式计算与批处理:两种不同的“世界观”
先聊聊批处理。说白了,批处理就是“攒够了再干”。你把过去一天、一小时的数据攒成一个文件,然后一次性跑个 MapReduce 或者 Spark 任务,算出结果。我刚开始做大数据那会儿,用的就是这种模式。每天凌晨跑个定时任务,算昨天的报表。数据量大?没关系,慢慢跑,反正不赶时间。
流式计算呢?正好反过来。它是“来一条算一条”。数据像水流一样源源不断地进来,系统得在毫秒级内做出反应。比如你在淘宝上买东西,下单后立刻看到“库存-1”,这就是流计算在背后撑着。
这两种模式,核心区别在哪?我列个表,你一看就明白:
| 维度 | 批处理 | 流式计算 |
|---|---|---|
| 数据范围 | 全量数据(过去N小时/天) | 实时到达的单条或微批次数据 |
| 延迟要求 | 分钟级~小时级 | 毫秒级~秒级 |
| 计算模型 | 一次性触发,全量扫描 | 持续运行,增量处理 |
| 典型引擎 | MapReduce、Hive、Spark SQL | Flink、Storm、Kafka Streams |
| 状态管理 | 无状态(每次从头算) | 有状态(维护中间结果) |
你想想看,批处理就像拍照片,咔嚓一下,记录的是某个时间点的快照。流式计算呢,像录像,每一帧都在变化。这两种模式各有各的适用场景,但问题来了——很多业务场景,你既需要低延迟的实时结果,又需要全量数据的精确回溯。这就引出了经典的 Lambda 架构。
1.2 Lambda 架构的痛点:两套代码,双倍痛苦
Lambda 架构,我估计很多老哥都听过。它的思路很简单:
- 批处理层:处理全量数据,保证最终结果的准确性。
- 流处理层:处理实时数据,提供低延迟的近似结果。
- 服务层:把两边的结果合并,对外提供服务。
听起来挺合理对吧?但我在项目中实际落地过之后,发现这玩意儿就是个“美丽的陷阱”。
Lambda 架构的痛点,我总结为三点:
- 维护两套代码:批处理和流处理各写一套逻辑,开发成本翻倍。你想想看,同样的业务逻辑,用 SQL 写一遍,再用 Flink API 写一遍,还得保证结果一致。这不是折磨人吗?
- 数据一致性难保证:批处理的结果和流处理的结果,在服务层合并时,经常出现“对不上”的情况。比如实时层算出的 UV 是 100 万,批处理层算出来是 98 万。到底信哪个?
- 运维复杂度高:两套集群、两套调度、两套监控。出问题的时候,你得同时排查两个系统。我记得有一次半夜被叫起来,说实时大屏数据不动了。查了半天,发现是批处理层的 Hive 任务把临时表给覆盖了,导致服务层的数据被污染。
说白了,Lambda 架构就是“用复杂度换实时性”。在数据量不大、业务逻辑简单的时候还能凑合。一旦规模上来,这玩意儿就是个定时炸弹。
1.3 Kappa 架构的演进:用一套引擎统一天下
既然 Lambda 架构这么痛苦,那有没有更好的方案?有,就是 Kappa 架构。
Kappa 架构的核心思想很简单:只用一套流处理引擎,搞定所有事情。批处理?不存在的。你把全量数据也当成流,从头到尾“重放”一遍,不就等于做了一次批处理吗?
我举个例子。假设你要算过去 30 天的用户活跃数。在 Lambda 架构里,你得用批处理跑全量数据,再用流处理跑实时增量。但在 Kappa 架构里,你只需要把过去 30 天的数据全部重新输入到流处理引擎里,让它从头算一遍。结果一样,但只用了一套代码。
Kappa 架构的演进,其实反映了业界的一个共识:流和批的本质是一样的,只是时间窗口不同。批处理是“无限大的窗口”,流处理是“小窗口”。既然底层逻辑一样,为什么非要用两套引擎呢?
当然,Kappa 架构也不是银弹。它有个前提:你的数据源必须支持全量重放。比如 Kafka,你得把数据保留足够长的时间,或者有办法从外部存储(如 HDFS)重新导入。另外,如果数据量特别大,全量重放的成本也很高。但相比 Lambda 架构的两套代码维护成本,这点代价是值得的。
1.4 流批一体的核心价值:一套代码,两种语义
聊完了 Lambda 和 Kappa,咱们终于可以进入正题了——流批一体。
流批一体,说白了就是:用同一套 API 写代码,既能跑批处理,也能跑流处理。你写一个 SQL 或者 DataStream 程序,在批模式下跑,它就是批处理;在流模式下跑,它就是流处理。底层引擎自动优化执行计划,不需要你操心。
我个人认为,流批一体的核心价值体现在三个方面:
| 价值维度 | 具体体现 | 我的实际感受 |
|---|---|---|
| 开发效率 | 一套代码,两种运行模式 | 以前写两套代码要 2 周,现在 1 周搞定 |
| 数据一致性 | 批和流共享同一套状态和语义 | 再也不用半夜起来对数据了 |
| 运维简化 | 一套集群,一套监控 | 集群数量直接减半,运维成本下降 60% |
你可能会问:流批一体到底是怎么做到的?核心在于 状态复用。批处理和流处理,本质上都是对数据的“有状态计算”。批处理的状态是“全量快照”,流处理的状态是“增量快照”。如果能把这套状态管理统一起来,那批和流就能共用一套计算逻辑。
举个例子。Flink 的 Table API 和 SQL,就是典型的流批一体实现。你写一个 SELECT COUNT(*) FROM orders GROUP BY user_id,在批模式下,它会对全量数据做一次聚合;在流模式下,它会维护一个不断更新的计数器。底层用的都是同一套状态后端(比如 RocksDB),只是运行模式不同。
最后,我用一张图来总结本章的核心逻辑:
嗯,这张图把本章的核心逻辑串起来了。批处理和流处理,通过流批一体引擎统一起来,最终实现开发效率、数据一致性和运维简化三大价值。后面的章节,我们会深入探讨状态复用这个核心机制,看看它到底是怎么实现的。