4. Spark Streaming 基础:DStream、Receiver、批次间隔与 WordCount 入门案例

在贷后预警场景中,数据以持续流的形式到达(如还款流水、催收记录、逾期状态变更)。Spark Streaming 是构建实时预警管线的核心引擎。本章从最基础的抽象——DStream 出发,讲解数据如何被接收、如何按时间窗口切分,并通过经典的 WordCount 案例串联完整流程。

4.1 DStream:离散化数据流

DStream(Discretized Stream) 是 Spark Streaming 提供的高层抽象,表示一个连续的数据流。从内部实现看,DStream 本质上是一个由 RDD 序列 组成的“流”,每个 RDD 对应一个批次间隔内的数据。

概念 说明 贷后预警类比
DStream 连续数据流的逻辑表示 “逾期事件流”
RDD 序列 DStream 内部按时间切分的 RDD 集合 每 5 秒内的逾期事件快照
批次间隔 将流数据切分为 RDD 的时间窗口 预警检查周期(如 5s/10s)
转换操作 对 DStream 应用 map/filter/reduceByKey 等 过滤逾期金额 > 1000 的事件
输出操作 将结果写入外部系统(HDFS/DB/Kafka) 写入预警结果表
关键理解:DStream 不是“一条一条”处理数据,而是“一批一批”处理。批次间隔决定了实时性的粒度。在贷后预警中,5 秒的批次间隔意味着最长 5 秒的延迟,这对大部分预警场景是可接受的。

4.2 Receiver:数据接收器

Receiver 是 Spark Streaming 从外部数据源拉取数据的组件。每个 Receiver 作为一个长期运行的任务(Task)运行在 Executor 上,负责接收数据并存储到 Spark 的内存中,随后由 Streaming 框架按批次间隔切分为 RDD。

  • Receiver 类型:Kafka Receiver、Socket Receiver、File Receiver、Custom Receiver。
  • Receiver 数量:可以通过 spark.streaming.blockInterval 和并行度控制。
  • 可靠性:启用 WAL(Write Ahead Log)时,Receiver 先将数据写入 HDFS 日志,再处理,防止 Driver 重启后数据丢失。
贷后预警注意点:Receiver 的并行度直接影响吞吐量。如果单 Receiver 成为瓶颈,应使用 Kafka Direct 方式(无 Receiver)或增加 Receiver 数量。在预警场景中,建议使用 Kafka Direct API 以获得更好的容错性和背压控制。

4.3 批次间隔(Batch Interval)

批次间隔是 Spark Streaming 的核心时间参数,决定了流数据被切分的粒度。通过 StreamingContext 构造函数或 spark.streaming.batchDuration 配置。

批次间隔 延迟 吞吐量 适用场景
1 秒 低(~1s) 低 高频交易预警、实时风控
5 秒 中(~5s) 中 贷后逾期监控、催收队列
10 秒 较高(~10s) 高 批量报表、非实时预警
选择建议:贷后预警通常选择 5 秒作为默认批次间隔。如果数据量极大(如百万级事件/秒),可适当增大到 10 秒,并配合背压(Backpressure)机制防止系统过载。

4.4 WordCount 入门案例:完整流程

以下通过经典的 WordCount 案例,演示 Spark Streaming 从数据接收、批次切分、转换计算到结果输出的完整链路。案例使用 Socket 作为数据源,模拟实时文本流。

4.4.1 案例架构图

Spark Streaming WordCount 案例架构 Socket 数据源 nc -lk 9999 Receiver 数据接收 & 存储 DStream RDD 序列 (批次) flatMap + map 分词 & 映射 reduceByKey 按 key 聚合 print() 批次间隔 = 5s 每 5s 生成一个 RDD 包含该窗口内所有数据

4.4.2 完整代码实现

import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}

// 1. 创建 StreamingContext,批次间隔 5 秒
val conf = new SparkConf().setAppName("LoanWarningWordCount").setMaster("local[2]")
val ssc = new StreamingContext(conf, Seconds(5))

// 2. 创建 Socket 数据源 DStream(Receiver 方式)
//    连接到本地 9999 端口,模拟实时文本流
val lines: DStream[String] = ssc.socketTextStream("localhost", 9999)

// 3. 转换操作:分词 → 映射为 (word, 1) → 按 key 聚合
val words = lines.flatMap(_.split(" "))
val pairs = words.map(word => (word, 1))
val wordCounts = pairs.reduceByKey(_ + _)

// 4. 输出操作:打印每个批次的结果
wordCounts.print()

// 5. 启动流计算
ssc.start()
ssc.awaitTermination()

4.4.3 执行步骤

  1. 启动数据源:在终端执行 nc -lk 9999,输入文本行。
  2. 提交 Spark 应用:运行上述代码,StreamingContext 开始监听 9999 端口。
  3. 观察输出:每 5 秒打印一次该窗口内的单词计数结果。

4.4.4 数据流与 RDD 切分示意图

DStream 内部 RDD 切分示意 T0 T1 (5s) T2 (10s) T3 (15s) T4 (20s) 连续数据流 RDD-1 RDD-2 RDD-3 RDD-4 批次 1 批次 2 批次 3 批次 4

4.5 本章小结

  • DStream 是 Spark Streaming 的核心抽象,本质是 RDD 序列。
  • Receiver 负责数据接入,支持多种数据源,贷后预警推荐 Kafka Direct 方式。
  • 批次间隔 决定实时性与吞吐量的平衡,贷后场景默认 5 秒。
  • WordCount 案例 完整演示了从 Socket 接收、DStream 转换到结果输出的全流程,是理解 Streaming 编程模型的最佳起点。