4. 流式计算引擎选型:Flink、Spark Streaming、Kafka Streams 对比与考量
说到实时特征平台,最核心的决策之一就是选哪个流式计算引擎。我见过不少团队,一上来就追着社区热度跑,结果后期运维成本高得吓人。今天咱们就掰开揉碎,把 Flink、Spark Streaming、Kafka Streams 这三兄弟的底裤都扒一扒。
先亮明我的观点:没有银弹。每个引擎都有自己的脾气,选型本质上是权衡你的业务场景、团队能力和基础设施。
4.1 三驾马车:核心差异一览
先看一张总览表,后面我们再逐个拆解。
| 维度 | Apache Flink | Spark Streaming | Kafka Streams |
|---|---|---|---|
| 计算模型 | 真正的逐条流处理 | 微批次(Micro-Batch) | 逐条流处理(KIP-554后) |
| 状态管理 | 内置 Keyed State + RocksDB | 基于 RDD 的 Checkpoint | 内置状态存储(RocksDB) |
| Exactly-Once | 端到端支持 | 端到端支持 | 端到端支持(需配置) |
| 延迟 | 毫秒级 | 秒级(批次间隔决定) | 毫秒级 |
| 部署模式 | 独立集群 / YARN / K8s | 独立集群 / YARN / K8s | 嵌入式库(无需集群) |
| 编程语言 | Java / Scala / Python | Java / Scala / Python / R | Java / Scala |
| 与 Kafka 集成 | Kafka Connector 成熟 | Kafka Connector 成熟 | 原生集成(Kafka 原生) |
核心结论:Flink 是实时特征平台的“重武器”,适合复杂状态计算;Spark Streaming 适合已有 Spark 生态的团队;Kafka Streams 是轻量级“特战小队”,适合 Kafka 原生场景。
4.2 Apache Flink:实时计算的“扛把子”
我个人习惯把 Flink 叫做“实时计算界的 Linux”。为什么?因为它把流处理这件事做到了极致。
Flink 的核心优势在于它的真正的逐条处理模型。它不是攒一批再算,而是来一条处理一条。这意味着什么?意味着你的特征延迟可以压到毫秒级。我在做金融风控特征平台时,要求特征延迟不超过 50ms,Flink 是唯一能稳定达标的引擎。
另一个让我爱不释手的是它的状态管理。Flink 的 Keyed State 配合 RocksDB,可以轻松管理 TB 级别的状态。你想想看,做用户实时画像,每个用户可能有几百个特征,状态量巨大。Flink 的增量 Checkpoint 机制,让大状态下的容错不再是噩梦。
我的经验:Flink 的 Checkpoint 间隔不要设得太短。我见过有人设成 100ms,结果集群一半资源都在做快照。建议生产环境设 1-3 秒,配合增量 Checkpoint,效果最好。
当然,Flink 也有它的“脾气”。部署运维成本高,学习曲线陡峭。如果你团队里没人啃过 Flink 源码,遇到性能问题可能会抓瞎。
4.3 Spark Streaming:生态巨人的“实时触角”
Spark Streaming 本质上是个“伪装成实时的批处理”。它把流切成一堆小批次,每个批次用 Spark 引擎去算。这个设计有好有坏。
好处很明显:生态无敌。如果你团队已经用 Spark 做离线 ETL,那 Spark Streaming 的学习成本几乎为零。同样的 DataFrame API,同样的调优经验,直接复用。我在一个电商项目中,离线特征和实时特征共用一套 Spark 代码,只是把 read 从 parquet 换成了 Kafka,开发效率极高。
坏处也很致命:延迟天花板。微批次模型决定了它的延迟下限是批次间隔。你设 1 秒,延迟就是 1 秒+;设 500ms,延迟就是 500ms+。而且批次间隔越小,调度开销占比越大,吞吐量会下降。所以 Spark Streaming 适合秒级延迟的场景,毫秒级就别想了。
避坑指南:我曾经在一个项目里把 Spark Streaming 的批次间隔设成 200ms,结果发现吞吐量只有正常情况下的 30%。后来改成 2 秒,配合异步处理,才把性能拉回来。记住:Spark Streaming 不是用来做低延迟的。
另外,Spark Streaming 的 Structured Streaming 模式虽然改进了不少,但本质上还是微批次。它的 Continuous Processing 模式号称是逐条处理,但生产环境我还没见过谁敢大规模用。
4.4 Kafka Streams:轻量级的“嵌入式战士”
Kafka Streams 是个异类。它不需要独立集群,就是一个 Java 库,嵌在你的应用里跑。这个设计理念很有意思:把流处理变成应用的一部分。
它的优势非常突出:
- 部署极简:打成 jar 包就能跑,不需要运维一套集群
- 与 Kafka 原生集成:Exactly-Once、分区分配、消费进度管理,Kafka 帮你搞定
- 延迟低:逐条处理,毫秒级延迟
但它的短板也很明显:能力边界有限。Kafka Streams 适合做简单的 ETL、过滤、聚合、Join。一旦涉及到复杂的多流 Join、大状态管理、窗口计算,它的表达能力就不如 Flink 了。而且它只支持 Java/Scala,Python 开发者只能干瞪眼。
我个人的使用场景是:轻量级特征计算。比如从 Kafka 读用户点击事件,实时计算最近 5 分钟的点击率,然后写回 Kafka。这种场景用 Kafka Streams 最合适,代码量少,运维成本几乎为零。
小技巧:Kafka Streams 的状态存储默认使用 RocksDB,但要注意内存配置。我遇到过因为堆外内存没设对,导致频繁 Full GC 的情况。建议把 state.store.cache.max.bytes 和 buffered.records.per.partition 调小一点。
4.5 选型考量因素:我的决策框架
说了这么多,到底怎么选?我总结了一个决策框架,分为四个维度:
- 延迟要求:毫秒级选 Flink 或 Kafka Streams;秒级选 Spark Streaming
- 状态复杂度:大状态、复杂窗口、多流 Join 选 Flink;简单状态选 Kafka Streams
- 团队能力:有 Spark 背景选 Spark Streaming;有 Java 功底选 Flink 或 Kafka Streams
- 基础设施:已有 Kafka 集群且不想引入新系统,选 Kafka Streams;已有 YARN/K8s 集群,选 Flink 或 Spark Streaming
下面这张图可以帮你快速定位:
4.6 实战建议:不同场景的推荐组合
最后,我给出几个我在项目中验证过的组合方案:
- 金融风控特征平台:Flink + Kafka。毫秒级延迟,大状态管理,Exactly-Once 语义,这是标配。
- 电商实时推荐:Flink 做复杂特征计算 + Kafka Streams 做简单特征聚合。分层架构,各取所长。
- IoT 设备监控:Spark Streaming + Kafka。秒级延迟够用,Spark 的 MLlib 可以直接做异常检测。
- 日志实时清洗:Kafka Streams。简单 ETL,不需要集群,一个 jar 包搞定。
重要提醒:不要为了“技术炫酷”而选型。我见过一个团队,明明只需要做简单的日志过滤,非要上 Flink,结果运维成本比开发成本还高。记住:最简单的方案,往往是最好的方案。