实时数据处理在互联网、电商、物流、金融等领域均有大量应用,面对海量流式数据,Spark Streaming 和 Flink 成为两大主流开源引擎。本文基于生产环境需求,从整体架构、编程模型、容错机制、性能表现、实践案例等维度进行深入对比,并给出选型建议。
业务场景
核心需求
| 方案 | Spark Streaming | Flink | |------------------|--------------------------------|--------------------------------| | 编程模型 | 微批处理(DStream / Structured Streaming) | 纯流式(DataStream API) | | 延迟 | 100ms~1s(取决批次间隔) | 毫秒级 | | 容错机制 | 检查点+WAL | 本地状态快照+分布式快照(Chandy-Lamport) | | 状态管理 | 基于 RDD 的外部存储 | 内置 Keyed State,支持 RocksDB | | 事件时间处理 | 支持(Structured API) | 强大的 Watermark 支持与事件时间 | | 调度模式 | Driver/Executor | JobManager/TaskManager | | 生态集成 | 与 Spark ML、GraphX 无缝集成 | 支持 CEP、Table/SQL、Blink Planner |
Spark Streaming
Apache Flink
延迟敏感场景
批+流一体化需求
复杂事件处理(CEP)
机器学习模型在线评估
资源与社区支持
以下示例演示同一数据源下,分别使用 Spark Structured Streaming 和 Flink DataStream 统计每分钟访问量。
import org.apache.spark.sql.{SparkSession, DataFrame}
import org.apache.spark.sql.functions._
object SparkStreamingApp {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder()
.appName("SparkStreamingCount")
.getOrCreate()
// 从 Kafka 读取数据
val df: DataFrame = spark.readStream
.format("kafka")
.option("kafka.bootstrap.servers", "broker1:9092,broker2:9092")
.option("subscribe", "access_logs")
.load()
// 假设 value = JSON,包含 timestamp 字段
val logs = df.selectExpr("CAST(value AS STRING)")
.select(from_json(col("value"), schemaOf[AccessLog]).as("data"))
.select("data.timestamp")
// 按分钟窗口聚合
val result = logs
.withColumn("eventTime", to_timestamp(col("timestamp")))
.groupBy(window(col("eventTime"), "1 minute"))
.count()
val query = result.writeStream
.outputMode("update")
.format("console")
.option("truncate", false)
.trigger(processingTime = "30 seconds")
.start()
query.awaitTermination()
}
}
配置(application.conf):
spark {
streaming.backpressure.enabled = true
streaming.kafka.maxRatePerPartition = 10000
}
public class FlinkStreamingApp {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.enableCheckpointing(60000); // 60s
env.setStateBackend(new RocksDBStateBackend("hdfs://namenode:8020/flink/checkpoints", true));
// Kafka Source
Properties props = new Properties();
props.setProperty("bootstrap.servers", "broker1:9092,broker2:9092");
props.setProperty("group.id", "flink-group");
DataStream stream = env
.addSource(new FlinkKafkaConsumer<>(
"access_logs",
new SimpleStringSchema(),
props
));
// 解析 JSON 并提取时间戳
DataStream logs = stream
.map(json -> parseJson(json, AccessLog.class))
.assignTimestampsAndWatermarks(
WatermarkStrategy
.forBoundedOutOfOrderness(Duration.ofSeconds(5))
.withTimestampAssigner((log, ts) -> log.getTimestamp())
);
// 按分钟窗口统计
logs
.keyBy(log -> "all")
.window(TumblingEventTimeWindows.of(Time.minutes(1)))
.process(new ProcessWindowFunction, String, TimeWindow>() {
@Override
public void process(String key, Context ctx, Iterable elements, Collector> out) {
long count = StreamSupport.stream(elements.spliterator(), false).count();
out.collect(new Tuple2<>(ctx.window().toString(), count));
}
})
.print();
env.execute("FlinkStreamingCount");
}
}
本文从架构原理、编程模型、容错与状态管理、性能表现及生态集成等多维度对比了 Spark Streaming 与 Flink。总体而言:
结合已有技术栈和团队经验进行选型,才能在生产环境中事半功倍。