2. 实时计算引擎选型对比:Flink vs Spark Streaming vs Kafka Streams
做实时特征任务,选哪个引擎?
这个问题我几乎每次跟团队讨论架构时都会被问到。说实话,没有银弹。Flink、Spark Streaming、Kafka Streams 各有各的脾气。我这些年三个引擎都用过,踩过坑也填过坑。今天咱们就掰开揉碎聊聊,不同场景下它们的成本模型到底差在哪。
2.1 三驾马车:核心差异速览
先给个全景图。这三个引擎的定位其实不太一样:
- Flink:真正的流式计算引擎。事件驱动,状态管理强,精确一次语义是原生能力。
- Spark Streaming:本质是微批次。把流切成小批,用 Spark 的批处理引擎跑。延迟在秒级。
- Kafka Streams:轻量级库,不是框架。嵌入你的应用里,依赖 Kafka 做状态和容错。
我习惯用一个比喻:Flink 像专业赛车手,为赛道而生;Spark Streaming 像 SUV,能越野也能跑高速;Kafka Streams 像自行车,灵活轻便,但别指望它拉重货。
选型核心原则:别只看性能指标。要看你的团队熟悉什么、你的基础设施是什么、你的特征任务对延迟和状态的敏感度有多高。
2.2 成本模型拆解:不止是机器钱
说到成本,很多人第一反应是“哪个引擎省机器”。其实成本模型要算四笔账:
| 成本维度 | Flink | Spark Streaming | Kafka Streams |
|---|---|---|---|
| 计算资源 | 中等偏高。状态后端 + checkpoint 吃内存和磁盘 | 高。微批次调度 + shuffle 吃 CPU 和网络 | 低。嵌入应用,无额外调度开销 |
| 存储资源 | 依赖状态后端(RocksDB 或 Heap),需要本地磁盘 | 依赖 HDFS/S3 做 checkpoint,存储成本高 | 依赖 Kafka 内部 topic,存储成本可控 |
| 运维成本 | 高。需要 Flink 集群 + JobManager HA | 高。需要 YARN/K8s + Spark 集群 | 低。无独立集群,随应用部署 |
| 开发成本 | 中等。API 丰富但学习曲线陡 | 中等。Spark SQL 生态好,但微批次思维要转 | 低。纯 Java 库,API 简洁 |
你看,Flink 和 Spark Streaming 的运维成本都不低。我曾经在一个项目里,Flink 集群挂了,排查了半天发现是 JobManager 的堆内存配置不合理。嗯,这种坑只有自己踩过才知道疼。
2.3 场景一:高吞吐、低延迟、强状态
这是 Flink 的主场。
比如实时特征计算中的滑动窗口聚合、CEP 模式匹配、多流 join。这些任务对状态一致性要求极高,Flink 的精确一次语义和分布式快照机制是天然优势。
成本模型上,Flink 的瓶颈通常在状态后端。我建议:
- 状态量小于 10GB:用 Heap StateBackend,性能最好
- 状态量 10GB~100GB:用 RocksDB,但注意调优内存和磁盘 I/O
- 状态量超过 100GB:考虑拆分任务或改用其他方案
我的经验:Flink 的 checkpoint 间隔别设太短。默认 500ms 太激进,我一般设 3~5 秒。太频繁的 checkpoint 反而会拖慢吞吐,得不偿失。
2.4 场景二:批流一体、已有 Spark 生态
如果你的团队已经重度使用 Spark,做 ETL、离线训练、报表分析,那 Spark Streaming 是自然选择。
成本优势在于复用。同一套集群、同一套运维体系、同一套代码规范。你想想看,不用再单独维护一套 Flink 集群,运维成本直接砍半。
但要注意,Spark Streaming 的微批次架构决定了它的延迟下限。我见过有人非要用 Spark Streaming 做毫秒级特征计算,结果折腾半天还是放弃了。说白了,工具选错了场景,再优化也白搭。
避坑指南:Spark Streaming 的背压机制在 2.x 版本里不够智能。我曾经遇到数据洪峰时,batch 堆积导致 OOM。后来升级到 3.x 并开启了 Dynamic Allocation 才缓解。如果你还在用 2.x,建议尽早升级。
2.5 场景三:轻量级、低运维、Kafka 原生
Kafka Streams 是我个人比较喜欢的一个选择,尤其是做简单的特征转换、过滤、富化这类任务。
它的成本模型很清晰:
- 没有独立集群,随应用部署在容器或物理机上
- 状态存储在 Kafka 的 changelog topic 里,天然持久化
- 弹性伸缩靠调整分区数,不需要额外调度器
我有个项目,用 Kafka Streams 做实时用户画像特征计算。每天处理几十亿条事件,只用了 8 台 8C16G 的机器。换成 Flink 至少需要 12 台,而且还要搭集群。这就是轻量级的优势。
但 Kafka Streams 也有短板:
- 不支持精确一次语义(只能做到至少一次)
- 状态查询不方便,没有 Flink 的 Queryable State
- 复杂窗口操作实现起来比较费劲
2.6 选型决策树:一张图说清楚
下面这张图是我自己总结的选型逻辑,帮你快速定位:
2.7 成本对比实战:一个特征任务的账单
拿一个真实的特征任务举例:实时计算用户过去 1 小时的点击率,数据量 10 万 QPS,状态量约 50GB。
我分别用三个引擎做过方案评估,结果如下:
| 项目 | Flink | Spark Streaming | Kafka Streams |
|---|---|---|---|
| 机器数量 | 12 台 8C16G | 16 台 8C16G | 8 台 8C16G(嵌入应用) |
| 月机器成本 | 约 1.2 万 | 约 1.6 万 | 约 0.8 万 |
| 运维人力 | 0.5 人月 | 0.5 人月 | 0.1 人月 |
| 开发周期 | 2 周 | 3 周 | 1 周 |
| 延迟 P99 | 80ms | 2.5s | 120ms |
你看,Kafka Streams 在机器成本和运维成本上优势明显,但延迟比 Flink 略高。Spark Streaming 最贵,延迟也最高,但如果你团队 Spark 能力强,开发成本可以忽略。
我的建议:别只看机器成本。运维人力和开发周期也是真金白银。我见过一个团队为了省机器钱选了 Kafka Streams,结果状态管理搞不定,最后又重写成 Flink,反而多花了两倍时间。
2.8 总结:选型没有标准答案
说了这么多,其实就一句话:场景决定选型,选型决定成本。
我个人习惯的做法是:
- 新项目、低延迟、强状态 → Flink
- 已有 Spark 生态、秒级延迟可接受 → Spark Streaming
- 轻量级特征转换、低运维、Kafka 原生 → Kafka Streams
嗯,最后提醒一句:别迷信某个引擎。工具是死的,业务是活的。选型前先想清楚你的特征任务到底要什么,再动手。