/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
Spark Streaming 架构深度拆解:微批处理模型、Receiver 与 Direct 模式对比
1. Spark Streaming 基本概念与架构
Spark Streaming 是 Apache Spark 平台上的一个核心组件,用于处理实时数据流。它构建于 Spark Core 之上,提供了高吞吐量、容错的流处理能力。与传统的流处理框架不同,Spark Streaming 采用微批处理(Micro-batching)模型,将实时数据流视为一系列小的批处理任务来处理。
DStream (Discretized Stream,离散化流) 是 Spark Streaming 的基本抽象,它代表一个连续的数据流。从逻辑上看,DStream 就是一系列 RDDs (弹性分布式数据集) 的序列,每个 RDD 包含特定时间间隔内接收的数据。DStream 可以从数据源如 Kafka、Flume、Kinesis、Twitter 等创建,也可以通过对其他 DStream 应用转换操作得到。
Spark Streaming 的整体架构包括数据输入、数据处理和数据输出三个主要部分:
| Spark Streaming 整体架构图展示 Spark Streaming 的核心组件与数据流向数据源(Kafka/Flume等)数据接收(Receiver/Direct)数据处理(DStream操作)数据输出(HDFS/DB等)Spark Core(执行引擎) |
Spark Streaming 的核心是将实时流数据分解成小的批次(batch),然后使用 Spark Core 的 RDD 处理这些批次。批次大小(batch interval)是一个关键配置参数,决定了处理的延迟和吞吐量,通常设置为 0.5-2 秒之间。
2. 微批处理模型详解
Spark Streaming 采用微批处理模型来处理实时数据流,这是它区别于其他流处理框架的关键特征。微批处理模型将连续的数据流离散化为一系列小的批次,每个批次包含在一个特定时间窗口内接收的所有数据。
微批处理模型的核心概念包括:
| 微批处理模型时序图展示微批处理模型如何将连续数据流离散化为批次时间线0s1s2s3s4s5s连续数据流………..数据流不间断地到达………..微批处理模型批次1批次2批次3数据处理1s内数据处理1s内数据处理1s内数据处理处理延迟:约1s批次间隔:1s |
微批处理模型的优点:
微批处理模型的缺点:
在 Spark Streaming 中,批次间隔是一个重要的配置参数,通常设置为 500ms 到 2 秒之间。较小的批次间隔可以降低延迟,但会增加任务调度的开销,而较大的批次间隔会增加处理延迟但可以提高吞吐量。
3. Receiver 模式工作原理与特性
Receiver 模式是 Spark Streaming 早期支持的一种数据接收模式。在 Receiver 模式中,Spark Streaming 应用会在每个工作节点上运行一个 Receiver 组件,该组件负责从数据源接收数据并将其存储在 Spark 的内存中(默认)或文件系统中。
Receiver 模式的工作流程如下:
| Receiver 模式数据流程图展示 Receiver 模式下数据从数据源到应用程序的流动过程数据源(Kafka/Flume)Spark Driver(主节点)Executor(工作节点)Receiver 1接收数据BlockManager管理数据块Receiver 2接收数据数据缓存(内存/磁盘)RDD生成批次处理数据处理结果输出 |
Receiver 模式的特点与优势:
Receiver 模式的缺点与局限性:
在 Receiver 模式中,为了提高数据接收的可靠性,可以使用 WAL(Write Ahead Log)机制。启用 WAL 后,Receiver 会将接收到的数据先写入日志文件,然后再复制到 Spark 的内存中。这样即使在 Driver 宕机的情况下,也不会丢失已接收的数据,提高了系统的容错性。
4. Direct 模式工作原理与特性
Direct 模式(也称为 No Receiver 模式)是 Spark Streaming 推荐的数据接收模式,特别是在处理 Kafka 这样的消息队列时。与 Receiver 模式不同,Direct 模式不需要在 Worker 节点上运行专门的 Receiver 组件,而是定期地从数据源直接读取数据。
Direct 模式的工作流程如下:
| Direct 模式数据流程图展示 Direct 模式下数据从数据源到应用程序的流动过程数据源(Kafka/Flume)Spark Driver(主节点)Executor(工作节点)Kafka分区1偏移量0-100偏移量管理记录已处理数据Kafka分区2偏移量50-150Driver查询获取最新偏移量任务分配按偏移量划分并行读取形成RDD |
Direct 模式的特点与优势:
Direct 模式的缺点与局限性:
Direct 模式特别适合以下场景:
在 Direct 模式中,偏移量的管理是关键。Spark 会将偏移量信息存储在可靠的存储中(如 ZooKeeper、HBase 或 Kafka 本身),确保在系统故障后能够恢复并继续处理。此外,Direct 模式还支持偏移量的手动控制,允许用户回退到之前的偏移量重新处理数据,这在调试或重新处理数据时非常有用。
5. 两种模式的对比与应用场景
Receiver 模式和 Direct 模式各有优势和适用场景,下面从多个维度进行对比分析。
| 数据接收方式 | 专用 Receiver 从数据源接收数据 | Driver 定期查询数据源,直接读取数据 |
| 资源占用 | 每个 Receiver 占用一个 Core | 无专用 Receiver,全部 Core 用于数据处理 |
| 并行性 | 无法并行读取多个分区数据 | 可并行读取多个分区数据 |
| 吞吐量 | 受限于 Receiver 处理能力 | 可通过并行读取提高吞吐量 |
| 延迟 | 较高,需经过缓存环节 | 较低,直接读取,减少中间环节 |
| 容错性 | 依赖 WAL 机制,可能丢数据 | 偏移量管理更可靠,数据一致性更好 |
| 编程复杂度 | 简单,高级抽象 | 复杂,需手动管理偏移量 |
| 适用场景 | 低延迟要求不高,需要简单编程模型 | 高吞吐量,需要精确一次处理,低延迟 |
| Receiver与Direct模式性能对比展示两种模式在不同性能指标上的对比Receiver模式与Direct模式性能对比吞吐量延迟资源利用率容错性中等较高较低一般高低高高Receiver模式Direct模式 |
上图展示了两种模式在不同性能指标上的对比。从图中可以看出,Direct 模式在吞吐量、资源利用率和容错性方面优于 Receiver 模式,而 Receiver 模式在延迟方面表现略差,但编程复杂度较低。
| Receiver与Direct模式适用场景对比展示两种模式在不同场景下的适用性Receiver模式与Direct模式适用场景对比数据量大小延迟要求数据一致性小/中数据量低延迟要求一般一致性大数据量高延迟要求强一致性Receiver模式Direct模式 |
上图展示了两种模式在不同场景下的适用性。从图中可以看出:
Receiver 模式更适合以下场景:
Direct 模式更适合以下场景:
在实际应用中,应根据具体业务需求和系统环境选择合适的数据接收模式。如果项目对性能要求不高,或者需要快速开发和部署,可以选择 Receiver 模式;如果项目对性能和一致性有较高要求,或者需要长期稳定运行,Direct 模式是更好的选择。
最小示例与注意事项
下面提供一个直接使用 Kafka 作为数据源的 Direct 模式最小示例:
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.kafka.KafkaUtils
// 创建 Spark 配置
val conf = new SparkConf().setAppName("SparkStreamingKafkaDirect").setMaster("local[*]")
// 创建 StreamingContext,批次间隔为 5 秒
val ssc = new StreamingContext(conf, Seconds(5))
// Kafka 配置
val kafkaParams = Map[String, Object](
"bootstrap.servers" -> "localhost:9092",
"key.deserializer" -> classOf[StringDeserializer],
"value.deserializer" -> classOf[StringDeserializer],
"group.id" -> "spark-streaming-group",
"auto.offset.reset" -> "latest",
"enable.auto.commit" -> (false: java.lang.Boolean)
)
// 要消费的 Kafka 主题
val topics = Set("spark-test")
// 使用 Direct API 创建 DStream
val stream = KafkaUtils.createDirectStream[String, String](
ssc,
PreferConsistent,
Subscribe[String, String](topics, kafkaParams)
)
// 处理数据 – 简单计数
val wordCounts = stream.flatMap(_.value().split(" ")).map((_, 1)).reduceByKey(_ + _)
// 打印结果
wordCounts.print()
// 启动 StreamingContext
ssc.start()
// 等待终止
ssc.awaitTermination()
注意事项:
通过合理选择数据接收模式和遵循上述注意事项,可以构建高效、稳定的 Spark Streaming 应用,满足实时数据处理需求。

