4. 流处理引擎选型:Flink vs Spark Structured Streaming
选流处理引擎,说白了就是选「命」。
我在好几个项目里都见过这种场景:架构师拍脑袋定了引擎,结果上线后延迟压不下去,或者吞吐上不来。改?成本高得吓人。所以这一章,我想跟你聊聊我这些年用 Flink 和 Spark Structured Streaming 的真实感受。
核心观点:没有最好的引擎,只有最合适的场景。Flink 擅长低延迟、复杂事件处理;Spark Structured Streaming 擅长高吞吐、与批处理一体化的场景。
4.1 两大引擎的「基因」差异
先看一张对比图,帮你快速建立整体认知。
4.2 低延迟与高吞吐的权衡
这是个老生常谈的问题,但真正做对的人不多。
Flink 的「真流」哲学
Flink 是真正的逐条处理引擎。每条数据来了,立即触发计算。我做过一个实时特征计算项目,要求延迟在 50ms 以内。Flink 配合 Kafka,端到端延迟稳定在 30ms 左右。但代价是什么?吞吐量受限于单条处理能力。
Spark Structured Streaming 的「微批」哲学
Spark 把流切成一个个小批次,默认 100ms 一个批次。你想想看,如果批次大小是 100ms,那延迟至少 100ms。但好处是吞吐量极高——我见过单节点每秒处理百万条数据的场景。
我的经验:如果业务要求延迟 < 100ms,别犹豫,选 Flink。如果延迟容忍度在 1-5 秒,且你已经在用 Spark 做批处理,Structured Streaming 能省下大量运维成本。
来看一个具体的对比表格:
| 维度 | Apache Flink | Spark Structured Streaming |
|---|---|---|
| 处理模型 | 真正的流处理(逐条) | 微批处理(默认 100ms) |
| 端到端延迟 | 毫秒级(10-100ms) | 秒级(100ms-10s) |
| 吞吐量 | 中等(受状态大小影响) | 高(批量处理优势) |
| 状态管理 | RocksDB / Heap,支持大状态 | StateStore + HDFS checkpoint |
| 事件时间语义 | 原生支持,精确 | 支持,但 watermark 机制较简单 |
| 运维复杂度 | 较高(需要调优参数多) | 较低(与 Spark 生态一致) |
4.3 状态后端的选择:RocksDB vs Heap
这是 Flink 用户最常纠结的问题。我踩过不少坑,跟你分享下。
Heap StateBackend
说白了就是把状态存在 JVM 堆内存里。优点是快——直接从内存读写,延迟极低。但缺点也很明显:受限于堆大小,状态一多就容易 OOM。
我曾经在一个项目里用 Heap 存用户画像特征,每个用户 1KB 状态,1000 万用户就是 10GB。JVM 堆设了 16GB,结果 Full GC 频繁,延迟飙升到秒级。嗯,那次教训很深刻。
RocksDB StateBackend
RocksDB 是 Facebook 开源的嵌入式 KV 存储,基于 LSM-Tree。它把数据存在本地磁盘,但利用内存做缓存。好处是状态可以很大——理论上只受限于磁盘空间。我见过存 100TB 状态的生产环境。
但 RocksDB 不是银弹。它的读写性能比 Heap 慢一个数量级,而且需要调优参数。比如 rocksdb.block.cache-size、rocksdb.writebuffer.size,调不好反而更慢。
避坑指南:我曾经遇到一个案例,RocksDB 的 compaction 导致 CPU 飙到 100%,延迟从 50ms 变成 5 秒。后来发现是默认的 compaction 策略不适合写密集场景。改成 Level Compaction + 增大 write buffer 才解决。
来看一个代码示例,展示如何在 Flink 中配置状态后端:
// 配置 RocksDB 状态后端
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
RocksDBStateBackend rocksDBStateBackend = new RocksDBStateBackend(
"hdfs://namenode:8020/flink-checkpoints", // checkpoint 路径
true // 增量 checkpoint
);
// 调优 RocksDB 参数
RocksDBOptions.TIMER_SERVICE_FACTORY.defaultValue();
rocksDBStateBackend.setPredefinedOptions(
PredefinedOptions.SPINNING_DISK_OPTIMIZED_HIGH_MEM
);
env.setStateBackend(rocksDBStateBackend);
env.enableCheckpointing(5000); // 5 秒一次 checkpoint
选型建议:
- 状态 < 10GB,延迟敏感:用 Heap。比如实时风控中的计数器、简单聚合。
- 状态 > 10GB,或不确定:用 RocksDB。比如用户画像、特征存储、长时间窗口。
- 注意:RocksDB 需要 SSD 磁盘,机械硬盘会严重拖慢性能。
4.4 实战中的选型决策树
我总结了一个简单的决策流程,帮你快速判断:
4.5 我的最终建议
做了这么多年实时计算,我越来越觉得:选型不是技术问题,是业务问题。
- 如果你做实时特征工程,需要毫秒级延迟、复杂状态管理、事件时间处理——Flink + RocksDB 是标配。
- 如果你做数据 ETL、报表、对延迟不敏感,但需要高吞吐、与批处理无缝切换——Spark Structured Streaming 更省心。
- 如果你不确定,从 Flink 开始。因为 Flink 能向下兼容 Spark 的场景,但反过来不行。
一个小技巧:在项目初期,用 Flink 的 MiniCluster 模式做原型验证,快速试错。等业务逻辑稳定了,再决定生产环境的部署方案。
记住一句话:流处理引擎选型,选的是未来三年的运维成本。别只看 POC 阶段的性能数据,多想想团队能不能 hold 住。