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 如何以微批处理模式集成特征服务,完成实时决策。

Structured Streaming 微批处理架构:信用额度定价 Kafka 交易流 Structured Streaming 微批处理(5s 间隔) 特征服务 Redis / HBase 定价决策 状态更新(额度消耗) 微批处理内部流程(每个批次) 读取批次数据 特征查询 额度计算 输出决策 状态更新

4.7 关键选择:微批 vs 连续

在信用额度定价系统中,我们选择 微批处理模式,原因如下:

  1. 聚合需求:额度计算需要按用户和时间窗口进行聚合(如 sum、max),连续处理不支持。
  2. 状态管理:需要维护用户额度使用状态,微批处理通过 flatMapGroupsWithState 提供强大的状态管理能力。
  3. 特征服务集成:微批处理可以在 foreachBatch 中批量查询特征服务,减少网络开销。
  4. 容错与一致性:微批处理提供成熟的 Exactly-once 语义,确保额度计算不重复、不丢失。
实践建议: 将微批处理间隔设置为 1-5 秒,可以在延迟和吞吐量之间取得良好平衡。对于信用额度场景,5 秒的延迟完全可接受,且能显著降低系统负载。