2. 实时计算引擎选型:Flink、Spark Streaming、Kafka Streams 对比与选型依据
做实时特征生产,第一步不是写代码,而是选引擎。
选错了,后面全是坑。我见过不少团队,一开始图省事选了某个框架,结果做到一半发现延迟压不下去,或者状态管理根本撑不住,最后只能推倒重来。嗯,今天我们就来聊聊 Flink、Spark Streaming 和 Kafka Streams 这三兄弟,到底该怎么选。
一句话总结:没有最好的引擎,只有最合适的场景。选型的关键在于你的延迟要求、状态规模、以及团队的技术栈积累。
2.1 三驾马车:核心差异速览
先看一张对比表,心里有个底。
| 维度 | Apache Flink | Spark Streaming | Kafka Streams |
|---|---|---|---|
| 计算模型 | 真正的流式计算(逐条处理) | 微批次(Micro-Batch) | 流式计算(基于Kafka分区) |
| 延迟 | 亚秒级(毫秒) | 秒级(取决于批次间隔) | 亚秒级(毫秒) |
| 状态管理 | 强大,支持 RocksDB 大状态 | 较弱,依赖外部存储 | 中等,基于 RocksDB |
| 语义保证 | Exactly-Once | Exactly-Once | Exactly-Once |
| 部署运维 | 需要独立集群(YARN/K8s) | 需要独立集群(YARN/K8s) | 嵌入应用,无需独立集群 |
| 学习曲线 | 中等偏难 | 中等(熟悉Spark的话) | 较易(熟悉Kafka的话) |
这张表能帮你快速过滤掉明显不合适的选项。比如,你的业务要求毫秒级延迟,那 Spark Streaming 基本可以排除了。但具体怎么选,还得往下看。
2.2 Apache Flink:实时特征生产的主力军
我个人习惯把 Flink 叫做「实时计算的正规军」。为什么?因为它从设计之初就是为流处理而生的。
核心优势:
- 真正的流处理: 数据来一条处理一条,没有微批次的「攒批」开销。延迟能做到真正的毫秒级。
- 强大的状态管理: 这是 Flink 最让我放心的地方。它内置了 RocksDB 作为状态后端,可以支撑 TB 级别的状态。我在项目中做过一个用户画像特征,每个用户维护一个长达 30 天的行为序列,状态量巨大,Flink 扛得稳稳的。
- 精确一次语义: 端到端的 Exactly-Once,对于金融、交易类场景是刚需。
- 事件时间处理: 天然支持乱序事件,Watermark 机制成熟。做实时特征时,数据晚到是家常便饭,Flink 处理起来很优雅。
我的经验: 如果你的特征生产需要复杂的窗口计算(比如滑动窗口、会话窗口),或者需要维护大量的用户状态,Flink 是首选。我做过一个实时推荐特征,需要每 5 分钟统计一次用户过去 1 小时的行为,Flink 的窗口 API 写起来非常顺手。
避坑指南:
- Flink 的 Checkpoint 机制虽然强大,但大状态下的 Checkpoint 耗时可能成为瓶颈。我曾经遇到过 Checkpoint 超时导致作业失败的情况,后来通过调整 Checkpoint 间隔和并发度解决了。
- Flink 的 SQL 层虽然发展很快,但复杂的状态操作还是建议用 DataStream API,更灵活可控。
2.3 Spark Streaming:批处理思维的流计算
Spark Streaming 本质上是对流数据做「微批次」处理。它把连续的数据流切成一个个小批次,然后用 Spark 的批处理引擎去算。
核心特点:
- 生态丰富: 如果你团队已经重度使用 Spark 做离线数仓,那么 Spark Streaming 的接入成本很低。SQL、MLlib、GraphX 都能复用。
- 吞吐量高: 微批次模式在处理大吞吐量数据时,性能表现不错。因为批次内可以做一些批处理优化。
- 延迟瓶颈: 这是硬伤。即使把批次间隔调到 500ms,实际延迟也在秒级。对于需要亚秒级响应的实时特征,它不太够用。
注意: Spark Streaming 的 Structured Streaming 虽然引入了「连续处理」模式,但生产环境中用得不多,成熟度不如 Flink。我建议还是把它当作「准实时」引擎来用。
适用场景:
- 对延迟要求不高的特征生产(比如分钟级更新的用户画像标签)。
- 团队 Spark 技术栈成熟,不想引入新引擎。
- 需要同时做流处理和批处理,希望统一技术栈。
2.4 Kafka Streams:轻量级嵌入式方案
Kafka Streams 是个异类。它不是一个独立的计算框架,而是一个 Java 库。你把它打成 jar 包,嵌在你的应用里就能跑。
核心优势:
- 零运维: 不需要搭建 Flink 或 Spark 集群。只要你有 Kafka,就能跑 Kafka Streams。部署成本和运维成本极低。
- 延迟低: 基于 Kafka 的消费-处理-生产模型,延迟能做到毫秒级。
- 与 Kafka 深度集成: 天然利用 Kafka 的分区机制做并行,状态存储也依赖 Kafka 的 Compacted Topic 做容错。
局限性:
- 状态规模受限: 虽然用了 RocksDB,但状态是本地存储的,无法像 Flink 那样做分布式状态管理。状态太大时,容易 OOM 或性能下降。
- 复杂窗口支持弱: 会话窗口、滑动窗口等复杂窗口的实现不如 Flink 方便。
- 调试困难: 因为是嵌入式的,出了问题很难像 Flink 那样通过 Web UI 查看作业状态。
我的建议: Kafka Streams 特别适合做「轻量级特征计算」。比如,在数据进入 Kafka 后,马上做一个简单的字段转换、过滤、或者基于单个分区的聚合。我有个项目就用它做实时特征清洗,代码量很少,部署也简单。
2.5 选型决策树:一张图说清楚
说了这么多,到底怎么选?我画了一张决策图,你跟着走一遍就知道了。
2.6 我的最终建议
如果你问我个人偏好,我会说:
- 新项目、实时特征生产为主: 无脑选 Flink。它是最专业的流处理引擎,生态也在快速完善。虽然学习曲线陡一点,但值得投入。
- 团队 Spark 技术栈深厚,延迟要求不高: 用 Spark Streaming 没问题,但别指望它能做毫秒级特征。
- 轻量级、快速迭代、不想运维集群: Kafka Streams 是个好选择。特别是你的特征逻辑比较简单,或者只是做数据预处理。
最后提醒一句: 选型不是一锤子买卖。我见过不少项目,一开始用 Spark Streaming,后来延迟要求变高,又迁移到 Flink。迁移成本很高。所以,建议你一开始就想清楚未来 1-2 年的需求,选一个「向上兼容」的引擎。