4. 流批一体技术选型:Flink、Spark Streaming、Kafka Streams 对比与选型策略
做流批一体架构,最绕不开的就是技术选型。我经常被问到:“到底该用 Flink、Spark Streaming 还是 Kafka Streams?” 说实话,没有银弹。每个框架都有自己的脾气,选错了后面改起来很痛苦。今天我就把这三家的底细掰开揉碎,结合我踩过的坑,给你一套可落地的选型策略。
4.1 三大引擎的定位差异
先看一张总览图,帮你快速建立全局认知。
4.2 核心能力对比
下面这张表我花了不少心思整理,把三个引擎在关键维度上的差异列清楚了。你选型时可以直接拿来当 checklist。
| 对比维度 | Apache Flink | Spark Streaming | Kafka Streams |
|---|---|---|---|
| 运行时模型 | 真正的流式处理(Dataflow 模型) | 微批次(Micro-Batch) | 记录级处理(Kafka 消费循环) |
| 延迟 | 毫秒级 | 秒级(批次间隔决定) | 毫秒级 |
| 精确一次语义 | 端到端支持(Checkpoint + 两阶段提交) | 仅输出端(需要幂等或事务) | 仅 Kafka 内部(通过事务 API) |
| 状态管理 | 强大(RocksDB + Heap,支持大状态) | 有限(基于 RDD 的 mapWithState) | 中等(RocksDB 内置,但受进程内存限制) |
| 事件时间支持 | 原生支持,Watermark 机制成熟 | Structured Streaming 支持,但精度受批次影响 | 需要手动处理(Kafka 时间戳) |
| SQL 支持 | Flink SQL(流批统一语法) | Spark SQL(批为主,流有限) | KSQL(轻量,功能有限) |
| 部署运维 | 需要集群(YARN/K8s/Standalone) | 需要集群(YARN/K8s/Standalone) | 嵌入应用,无额外运维 |
| 生态集成 | 广泛(Connector 丰富) | 非常广泛(Hadoop 生态) | 仅 Kafka 生态 |
我的经验: 如果你需要毫秒级延迟 + 精确一次 + 大状态,Flink 是唯一选择。Spark Streaming 的微批次架构在延迟上天生吃亏,但如果你已经有 Spark 技术栈,用它做流批一体也能接受。
4.3 选型策略:场景驱动
选型不能只看技术参数,得看你的业务场景。我一般按下面三个维度来决策。
4.3.1 场景一:全链路流批一体
说白了,就是同一套代码既要跑实时也要跑离线。比如实时数仓,白天跑实时 ETL,晚上跑全量回溯。
- 推荐:Flink
- 理由:Flink 的批流一体最彻底。批就是有界流,API 完全统一。我在做实时数仓时,同一个 Flink SQL 任务,白天消费 Kafka,晚上改成读 Hive,代码一行不改。
- 避坑:Flink 的批模式在 1.12 之后才成熟,如果你还在用 1.10 以下版本,批性能会差一些。
小技巧: Flink 的 TableEnvironment 可以同时注册 Kafka 表和 Hive 表,通过动态表(Dynamic Table)实现流批统一查询。我习惯把这种模式叫做「一套 SQL 跑天下」。
4.3.2 场景二:批为主,流为辅
你的核心场景是离线批处理,比如每天跑一次全量报表,但偶尔需要接入实时数据做近实时分析。
- 推荐:Spark Structured Streaming
- 理由:Spark 的批处理生态太强了。MLlib、GraphX、Spark SQL 都是业界标杆。你只需要把 Spark Streaming 当作批处理的一个补充。
- 避坑:Structured Streaming 的微批次架构在处理乱序数据时,Watermark 精度不如 Flink。我曾经有个项目,用 Spark 做实时 UV 统计,结果因为批次间隔设置不当,数据偏差了 5%。
注意: 如果你用 Spark Streaming,批次间隔(batch interval)不要设得太小。我见过有人设 100ms,结果集群 CPU 全耗在调度上了。一般建议 1-5 秒。
4.3.3 场景三:轻量级事件驱动
你的场景很简单:从 Kafka 消费数据,做点过滤、转换、聚合,再写回 Kafka。不需要外部存储,不需要大状态。
- 推荐:Kafka Streams
- 理由:零运维,嵌入应用,延迟极低。你想想看,一个 Spring Boot 应用里直接引入 Kafka Streams 依赖,就能跑流处理,多省事。
- 避坑:Kafka Streams 的状态管理受限于进程内存。如果你需要几十 GB 的状态,还是用 Flink 吧。
我的建议: Kafka Streams 最适合做「流式微服务」。比如订单状态流转、风控规则引擎、实时特征计算。我有个项目用 Kafka Streams 做实时推荐特征,延迟不到 10ms,爽得很。
4.4 选型决策树
为了让你更直观地做选择,我画了一张决策树。你顺着走一遍,基本就知道该用哪个了。
4.5 避坑指南
最后,分享几个我亲身踩过的坑,希望能帮你少走弯路。
坑一:Flink 的 Checkpoint 超时
我曾经有个 Flink 任务,状态 50GB,Checkpoint 总是超时。后来发现是 RocksDB 的并行压缩导致 I/O 打满。解决方案:调大 state.backend.rocksdb.thread.num,或者改用增量 Checkpoint。
坑二:Spark Streaming 的背压问题
Spark Streaming 默认不开启背压(Backpressure)。我有个项目数据量突然暴增,直接把 Kafka 消费 lag 拉到几百万。后来开启了 spark.streaming.backpressure.enabled=true,才稳住。
坑三:Kafka Streams 的分区再均衡
Kafka Streams 在实例重启或扩缩容时,会触发分区再均衡(Rebalance)。如果状态很大,再均衡过程可能很慢。我建议把 num.stream.threads 设大一点,减少实例数量,降低再均衡频率。
4.6 小结
选型没有标准答案,只有最适合你场景的答案。我的经验是:
- 如果你追求「真正的流批一体」,选 Flink,别犹豫。
- 如果你已经有 Spark 技术栈,批处理是核心,选 Spark Streaming,够用。
- 如果你只是做轻量级事件驱动,Kafka Streams 是最优雅的选择。