实时计算技术选型:Flink vs Spark Streaming vs Kafka Streams
做实时特征资产化,第一步就是选计算引擎。选错了,后面全是坑。
我见过不少团队,上来就拍脑袋选 Flink,理由是“大家都在用”。结果业务场景只是简单的消息过滤,Kafka Streams 几十行代码就能搞定,非得上个 Flink 集群,运维成本翻了好几倍。也见过迷信 Spark Streaming 的,处理秒级延迟的指标计算,结果反压调优调了一个月。
所以这一节,咱们把三个主流引擎掰开揉碎讲清楚。不吹不黑,只看场景。
三驾马车:核心定位速览
先给个直观的对比。我习惯用一张表来快速对齐认知:
| 维度 | Apache Flink | Spark Streaming | Kafka Streams |
|---|---|---|---|
| 计算模型 | 真正的流式计算(逐条处理) | 微批次(Micro-Batch) | 流式计算(Record-at-a-time) |
| 延迟 | 亚秒级(毫秒) | 秒级(默认批次间隔) | 亚秒级(毫秒) |
| 状态管理 | 内置 RocksDB + 定时快照 | 依赖外部存储(Redis/HBase) | 内置 RocksDB + 变更日志 Topic |
| 语义保证 | Exactly-Once(端到端) | Exactly-Once(微批次内) | Exactly-Once(需配合幂等生产者) |
| 部署模式 | 独立集群 / YARN / K8s | 独立集群 / YARN / K8s | 内嵌库(无需集群) |
| 学习曲线 | 中等偏难 | 中等 | 较易 |
这张表看下来,你可能会问:那是不是 Flink 最好?别急,咱们一个一个拆。
Apache Flink:实时特征资产化的主力军
我个人最常用 Flink 做特征工程。为什么?因为它把“流”这件事做到了骨子里。
Flink 的核心是 DataStream API。每条数据进来,立即触发计算,不攒批。这在做实时特征时特别重要——你想想看,用户点击行为发生的那一瞬间,特征就要更新,等不了那几秒的批次间隔。
Flink 在特征资产化中的典型场景:
- 复杂事件处理(CEP):用户浏览序列 -> 实时拼接成会话特征
- 多流 Join:用户画像流 + 实时行为流 -> 生成 enriched 特征
- 窗口聚合:5 分钟滑动窗口内的点击率、转化率特征
- 状态回溯:基于历史状态的实时特征计算(如用户累计消费金额)
我记得有一次做风控特征,需要把用户过去 30 天的交易行为做滑动窗口聚合。Flink 的 SlidingEventTimeWindows 配合 AggregateFunction,代码量不到 100 行,状态管理自动由 RocksDB 搞定。换成 Spark Streaming,你得自己维护一个外部状态存储,还要处理状态过期的问题。
不过 Flink 也有它的痛点。部署运维成本高,调优参数多。我见过新手把 checkpoint间隔 设成 1 秒,结果集群频繁快照,吞吐直接腰斩。嗯,这里要注意:checkpoint 间隔建议 30 秒以上,除非你的状态极小。
Spark Streaming:批处理思维的延续
Spark Streaming 本质上是“微批次”。它把流切成一堆小批次,每个批次用 Spark 的批处理引擎去算。
这种设计有好有坏。好处是:如果你团队已经熟悉 Spark 批处理,迁移成本很低。坏处是:延迟天然受批次间隔限制。
我做过一个实验:同样一个简单的计数任务,Flink 延迟在 100ms 以内,Spark Streaming 设成 1 秒批次间隔,延迟在 1.2 秒左右。如果你的业务能接受秒级延迟,Spark Streaming 完全够用。
什么时候选 Spark Streaming?
- 你已经有成熟的 Spark 批处理 pipeline,不想引入新引擎
- 特征计算以 T+1 或小时级为主,实时只是辅助
- 需要和 Spark MLlib 做模型推理集成
- 团队 Spark 能力强,Flink 经验不足
但要注意一个坑:反压。我曾经在一个项目中,用 Spark Streaming 处理高峰期的用户点击流,数据量突然暴涨,批次处理时间超过了批次间隔,导致背压堆积。调了 spark.streaming.backpressure.enabled 才稳住。而 Flink 的反压机制是天然的,不需要额外配置。
Kafka Streams:轻量级的选择
Kafka Streams 是个异类。它不是一个集群,而是一个 Java 库。你把它打成 jar 包,嵌在你的应用里就能跑。
它的核心思想是:流就是表,表就是流。通过 KTable 和 KStream 的转换,实现状态化计算。
我特别喜欢 Kafka Streams 的一点是:部署简单。不需要运维一个 Flink 或 Spark 集群,只需要一个 Kafka 集群就够了。对于中小团队来说,这能省下大量运维精力。
Kafka Streams 的局限性:
- 只能消费 Kafka 数据源,无法直接对接其他系统(如 MySQL CDC)
- 复杂窗口和 Join 能力弱于 Flink
- 状态大小受限于本地磁盘,不适合超大规模状态
- 调试和监控不如 Flink 方便
我曾经在一个 IoT 项目中,用 Kafka Streams 做设备状态的实时特征计算。每条设备上报数据,通过 groupByKey + reduce 聚合出最近 10 分钟的平均温度、最大电压等特征。代码简洁,部署就是一个 Spring Boot 应用,运维成本几乎为零。
但如果你要做跨多个 Topic 的复杂 Join,或者需要事件时间语义的精确窗口,Kafka Streams 就有点吃力了。这时候还是 Flink 更合适。
选型决策框架:一张图说清楚
下面这张图是我自己总结的选型决策流程,每次做技术选型我都会拿出来对照一下:
实战中的选型建议
说了这么多,到底怎么选?我给出三个典型场景的推荐:
场景一:实时风控特征计算
延迟要求:毫秒级。数据源:Kafka + MySQL CDC。状态:大(用户历史行为)。
推荐:Flink。原因:事件时间语义、Exactly-Once、大状态管理。
场景二:实时监控指标聚合
延迟要求:秒级。数据源:Kafka。状态:小(窗口聚合)。
推荐:Kafka Streams。原因:部署简单,运维成本低。
场景三:实时特征 + 离线批处理一体化
延迟要求:秒级。数据源:Kafka + HDFS。状态:中等。
推荐:Spark Streaming。原因:与 Spark 批处理共享代码和集群。
最后说一句:没有银弹。我见过用 Flink 做简单 ETL 的,也见过用 Kafka Streams 做复杂 CEP 的。选型不是比谁更牛,而是比谁更合适。你的团队擅长什么、你的运维能力有多强、你的业务容忍多高的延迟——这些才是决策的关键。