介绍
Spark Streaming 是 Apache Spark 生态系统中用于实时流数据处理的核心组件,基于 Spark Core 的批处理引擎实现了高吞吐量、可容错的流处理能力。它将连续的流数据切分为一系列微小的批处理任务(微批处理,Micro-Batch),复用 Spark 的核心优化(如 RDD/Dataset 抽象、内存计算、分布式调度),让开发者可以用与批处理一致的 API 处理实时数据。
应用场景
- 高吞吐量、低延迟要求不极致(秒级)的场景;
- 批流一体的业务(如离线计算 + 实时监控);
- 需要结合 Spark SQL/MLlib 做实时分析的场景(如实时推荐、实时风控)。
微批处理(Micro-Batch)
Spark Streaming 不是 真正的 “实时流”(流处理的严格定义是逐条处理),而是准实时(Near Real-Time) 处理:
- 将输入的连续数据流按固定时间间隔(如 1 秒)切分为“批次”(Batch);
- 每个批次对应一个 RDD/Dataset(Spark 的分布式数据抽象);
- Spark 引擎对每个批次执行批处理计算,输出结果;
- 最小延迟通常在百毫秒到秒级,适合高吞吐量、低延迟要求不极致的场景(如日志分析、指标统计)。
对比纯流处理(如 Flink):
| 特性 | Spark Streaming(微批) | Flink(纯流) |
|---|---|---|
| 处理模式 | 批处理模拟流 | 逐条实时处理 |
| 延迟 | 秒级 | 毫秒级 |
| 吞吐量 | 极高 | 高 |
| 编程模型 | 批流统一(与 Spark 批处理一致) | 独立流 API |
| 容错/状态管理 | 基于 RDD 容错 | 精准一次(Exactly-Once) |
核心概念
DStream(Discretized Stream)
Spark Streaming 的核心抽象,代表 连续的数据流,本质是一系列连续的 RDD/Dataset(每个 RDD 对应一个批次的数据)。
- 输入 DStream:从外部数据源(如 Kafka、Flume、TCP 套接字)接收数据生成;
- 转换 DStream:对输入 DStream 执行 map、filter、reduceByKey 等操作生成;
- 输出 DStream:将处理结果写入外部存储(如 HDFS、MySQL、Redis)。
批次间隔(Batch Interval)
切分数据流的时间粒度,由开发者在创建 StreamingContext 时指定(如 1 秒),决定了处理延迟的下限。
// 示例:创建 StreamingContext,批次间隔 1 秒
val sparkConf = new SparkConf().setAppName("StreamingDemo").setMaster("local[2]")
val ssc = new StreamingContext(sparkConf, Seconds(1))
窗口操作(Window Operations)
针对滑动时间窗口内的数据进行聚合,适用于“最近 N 分钟的统计”等场景,核心参数:
- 窗口长度(Window Length):窗口覆盖的时间范围(如 10 秒);
- 滑动步长(Slide Interval):窗口滑动的时间间隔(如 5 秒)。
// 示例:统计最近 10 秒、每 5 秒更新一次的单词计数 val wordCounts = words.map(word => (word, 1)) .reduceByKeyAndWindow( (a: Int, b: Int) => a + b, // 聚合函数 (a: Int, b: Int) => a - b, // 逆函数(优化性能) Seconds(10), // 窗口长度 Seconds(5) // 滑动步长 )
状态管理
- 无状态处理:每个批次的计算独立,不依赖历史数据(如单批次单词计数);
- 有状态处理:依赖历史批次数据(如累计计数),需开启 Checkpoint 持久化状态:
// 设置 Checkpoint 目录(HDFS/本地路径) ssc.checkpoint("hdfs://xxx/checkpoint") // 累计单词计数(updateStateByKey) val totalCounts = wordCounts.updateStateByKey { (newValues: Seq[Int], state: Option[Int]) => val sum = newValues.sum + state.getOrElse(0) Some(sum) }
优点
1. 批流统一编程模型
开发者可以用相同的 API(Scala/Java/Python)处理批数据(Spark Core)和流数据(Spark Streaming),降低学习成本。
2. 高容错性
基于 RDD 的不可变、可重算特性,任何节点故障都可通过重新计算 RDD 恢复数据;Checkpoint 机制可持久化元数据和状态,支持应用重启恢复。
3. 高吞吐量
复用 Spark 的内存计算、分布式调度和优化器,可处理每秒数百万条记录,支持水平扩展。
4. 丰富的数据源和输出
- 输入:Kafka、Flume、TCP 套接字、HDFS/S3、Kinesis 等;
- 输出:HDFS、MySQL、Redis、Elasticsearch、Kafka 等。
5. 集成 Spark 生态
可与 Spark SQL(流数据中执行 SQL 查询)、MLlib(实时机器学习)、GraphX(图计算)无缝集成。
缺点
- 延迟较高(秒级),不适合毫秒级实时场景(如高频交易);
- 微批模型对“事件时间”处理不够灵活(Spark 2.0 后引入 Structured Streaming 优化);
- 状态管理(如 updateStateByKey)在大规模场景下性能可能下降。
Spark Streaming vs Structured Streaming
Spark 2.0 后推出的 Structured Streaming 是 Spark Streaming 的下一代流处理引擎,解决了传统 DStream 的不足:
| 特性 | Spark Streaming(DStream) | Structured Streaming |
|——————————-|——————————————-|———————————|
| 抽象层 | DStream(RDD 序列)| DataFrame/Dataset(关系型抽象) |
| 处理模型 | 微批(固定批次)| 微批/连续处理(Continuous Processing,毫秒级) |
| 事件时间处理 | 弱支持 | 原生支持(水印、迟到数据处理) |
| API 易用性 | 底层 RDD 操作 | 高层 SQL/DataFrame API |
| 容错保证 | 至少一次(At-Least-Once)| 精准一次(Exactly-Once) |
建议:新开发的流处理应用优先使用 Structured Streaming,传统 DStream 已逐渐被替代。
六、简单示例(WordCount)
import org.apache.spark.streaming._
import org.apache.spark.streaming.StreamingContext._
object StreamingWordCount {
def main(args: Array[String]): Unit = {
// 1. 创建 StreamingContext
val conf = new org.apache.spark.SparkConf().setAppName("WordCount").setMaster("local[2]")
val ssc = new StreamingContext(conf, Seconds(1))
ssc.checkpoint("./checkpoint") // 开启 Checkpoint
// 2. 读取 TCP 套接字数据(nc -lk 9999 启动数据源)
val lines = ssc.socketTextStream("localhost", 9999)
// 3. 处理数据:切分单词 -> 计数
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map(word => (word, 1)).reduceByKey(_ + _)
// 4. 输出结果
wordCounts.print()
// 5. 启动流处理并等待终止
ssc.start()
ssc.awaitTermination()
}
}
总结
Spark Streaming 是基于微批模型的流处理框架,核心优势是批流统一、高吞吐量和生态集成,适合大多数准实时流处理场景。对于极致低延迟或复杂事件时间处理的场景,可选择 Structured Streaming 或 Flink,但 Spark Streaming 仍是理解 Spark 流处理核心思想的基础。