4. Spark Streaming 核心概念:DStream、Structured Streaming、微批处理与连续处理模式
在信用额度定价的实时决策场景中,数据流必须被高效、可靠地处理。Spark 提供了两代流处理引擎:基于 RDD 的 DStream(Spark Streaming)和基于 DataFrame/Dataset 的 Structured Streaming。理解它们的核心概念与处理模式,是构建流式定价决策系统的基础。
4.1 DStream:第一代流处理抽象
DStream(Discretized Stream)是 Spark Streaming 时代的核心抽象。它将连续的数据流切分成一系列微小的 RDD 批次,每个批次代表一个时间窗口内的数据。
- 本质:DStream 是一个 RDD 的序列,每个 RDD 包含一个时间间隔内的数据。
- 操作:支持 map、filter、reduceByKey 等 RDD 算子,以及窗口操作(window、reduceByWindow)。
- 状态管理:通过
updateStateByKey或mapWithState维护跨批次的状态(如用户累计额度使用量)。 - 局限:基于 RDD 的 API 较底层,处理延迟较高(通常秒级),且与 DataFrame/Dataset API 的整合不够自然。
信用额度场景示例: 使用 DStream 接收 Kafka 中的交易事件,每 5 秒一个批次,通过
updateStateByKey 维护每个用户的当日累计消费金额,当超过信用额度时触发告警。
4.2 Structured Streaming:第二代流处理引擎
Structured Streaming 基于 Spark SQL 引擎,将流数据视为“无界表”(Unbounded Table)。数据源源不断地追加到这张表中,用户使用标准的 DataFrame/Dataset API 进行查询,Spark 自动将其转化为增量执行计划。
| 特性 | DStream | Structured Streaming |
|---|---|---|
| 核心抽象 | RDD 序列 | 无界表(DataFrame/Dataset) |
| API | RDD 算子 | DataFrame/Dataset API(SQL 友好) |
| 处理语义 | At-least-once(需额外配置 Exactly-once) | Exactly-once(内置) |
| 延迟 | 秒级(微批) | 毫秒级(连续处理)或秒级(微批) |
| 状态管理 | updateStateByKey / mapWithState | groupBy + agg / flatMapGroupsWithState |
| 与特征服务集成 | 需手动管理连接 | 通过 foreachBatch 或 streaming.foreach 自然集成 |
推荐: 在信用额度定价系统中,优先使用 Structured Streaming。它提供更简洁的 API、更强的容错保证(Exactly-once),并且能更自然地与特征存储(如 Redis、HBase)进行交互。
4.3 微批处理模式(Micro-Batch Processing)
微批处理是 Spark Streaming 和 Structured Streaming 的默认处理模式。它将流数据切分成小批次(例如每 100ms 或 1s),每个批次作为一个作业提交到 Spark 集群执行。
- 工作原理:数据先被缓冲,达到触发间隔后,Spark 启动一个作业处理该批次数据。
- 优点:吞吐量高,容错机制成熟(基于 RDD 的血统),适合大多数实时场景。
- 缺点:存在固定的批次调度延迟,无法达到真正的毫秒级响应。
- 配置参数:
trigger(ProcessingTime("5 seconds"))控制批次间隔。
// Structured Streaming 微批处理示例:每 5 秒处理一次交易流
Dataset<Row> transactions = spark
.readStream()
.format("kafka")
.option("kafka.bootstrap.servers", "localhost:9092")
.option("subscribe", "credit-transactions")
.load();
Dataset<Row> creditUsage = transactions
.selectExpr("CAST(value AS STRING) as json")
.select(functions.from_json(functions.col("json"), schema).as("data"))
.select("data.userId", "data.amount", "data.timestamp");
creditUsage
.withWatermark("timestamp", "10 minutes")
.groupBy("userId", functions.window(functions.col("timestamp"), "5 minutes"))
.agg(functions.sum("amount").as("totalAmount"))
.writeStream()
.outputMode("update")
.trigger(Trigger.ProcessingTime("5 seconds")) // 微批触发间隔
.format("console")
.start();
4.4 连续处理模式(Continuous Processing)
连续处理是 Structured Streaming 在 Spark 2.3 引入的实验性模式,旨在实现毫秒级端到端延迟。与微批不同,连续处理使用长运行的任务(Long-running Tasks)持续读取和处理数据,无需批次调度。
- 工作原理:Driver 启动一组持续运行的 Executor 任务,这些任务不断从数据源拉取记录并立即处理。
- 优点:延迟极低(1-10ms),适合对延迟极度敏感的场景。
- 缺点:功能受限(仅支持 map-like 操作,不支持聚合、排序、水印等),容错机制较复杂(基于 epoch 标记)。
- 适用场景:简单的 ETL、过滤、映射操作,不适合复杂的信用额度聚合计算。
注意: 在信用额度定价系统中,通常需要聚合(如计算用户当日总消费)和状态管理,因此连续处理模式并不适用。微批处理模式是更稳妥、功能更完整的选择。
4.5 两种处理模式对比
| 对比维度 | 微批处理模式 | 连续处理模式 |
|---|---|---|
| 延迟 | 100ms ~ 数秒 | 1 ~ 10ms |
| 吞吐量 | 高(可批量处理) | 中(逐条处理) |
| 支持的操作 | 所有 DataFrame 操作(聚合、join、窗口) | 仅 map-like 操作(select、filter、map) |
| 状态管理 | 支持(groupBy + agg、flatMapGroupsWithState) | 不支持 |
| 容错 | 基于 RDD 血统,成熟稳定 | 基于 epoch 标记,实验性 |
| 信用额度定价适用性 | ✅ 推荐(支持聚合、状态、特征查询) | ❌ 不推荐(无法完成额度计算) |
4.6 架构总览:从数据源到定价决策
下图展示了在信用额度定价系统中,Structured Streaming 如何以微批处理模式集成特征服务,完成实时决策。
4.7 关键选择:微批 vs 连续
在信用额度定价系统中,我们选择 微批处理模式,原因如下:
- 聚合需求:额度计算需要按用户和时间窗口进行聚合(如 sum、max),连续处理不支持。
- 状态管理:需要维护用户额度使用状态,微批处理通过
flatMapGroupsWithState提供强大的状态管理能力。 - 特征服务集成:微批处理可以在
foreachBatch中批量查询特征服务,减少网络开销。 - 容错与一致性:微批处理提供成熟的 Exactly-once 语义,确保额度计算不重复、不丢失。
实践建议: 将微批处理间隔设置为 1-5 秒,可以在延迟和吞吐量之间取得良好平衡。对于信用额度场景,5 秒的延迟完全可接受,且能显著降低系统负载。