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 选型决策树:一张图说清楚

说了这么多,到底怎么选?我画了一张决策图,你跟着走一遍就知道了。

实时计算引擎选型决策树 你的实时特征需求 延迟要求 < 1秒? 状态规模 > 100GB? 团队有Spark基础? Flink / Kafka Streams Flink(RocksDB) Spark Streaming 复杂窗口/大状态? Flink Kafka Streams 选型建议 • 延迟敏感 + 大状态 → Flink • 延迟敏感 + 小状态 → Kafka Streams • 秒级延迟 + Spark生态 → Spark Streaming • 轻量级特征清洗 → Kafka Streams • 复杂窗口/CEP → Flink

2.6 我的最终建议

如果你问我个人偏好,我会说:

  • 新项目、实时特征生产为主: 无脑选 Flink。它是最专业的流处理引擎,生态也在快速完善。虽然学习曲线陡一点,但值得投入。
  • 团队 Spark 技术栈深厚,延迟要求不高: 用 Spark Streaming 没问题,但别指望它能做毫秒级特征。
  • 轻量级、快速迭代、不想运维集群: Kafka Streams 是个好选择。特别是你的特征逻辑比较简单,或者只是做数据预处理。

最后提醒一句: 选型不是一锤子买卖。我见过不少项目,一开始用 Spark Streaming,后来延迟要求变高,又迁移到 Flink。迁移成本很高。所以,建议你一开始就想清楚未来 1-2 年的需求,选一个「向上兼容」的引擎。