Spark Structured Streaming 详解

Structured Streaming 详解

(Spark 的声明式流处理引擎)

Structured Streaming 是 Spark 2.0+ 引入的基于 DataFrame/Dataset API 的流处理引擎,核心思想是将实时数据流视为一张持续追加的表(“无界表”),实现批流统一的编程模型。


一、核心设计理念
  1. “流即动态表”(Stream as Table)

    • 输入流 → 动态输入表
    • 查询操作 → 在动态表上连续执行
    • 结果输出 → 动态结果表 → 写入外部存储
  2. 端到端精确一次语义(Exactly-once)
    通过以下机制保证:

    • Source 偏移量跟踪(如 Kafka offset)
    • 容错状态存储(HDFS 检查点)
    • 幂等输出接收器

二、编程模型
1. 基础代码结构
import org.apache.spark.sql.SparkSession

val spark = SparkSession.builder()
  .appName("StructuredStreaming")
  .getOrCreate()

// 1. 定义输入源(Source)
val inputStream = spark.readStream
  .format("kafka")  // 支持 kafka, socket, file, rate 等
  .option("kafka.bootstrap.servers", "localhost:9092")
  .option("subscribe", "topic1")
  .load()

// 2. 数据处理(与批处理 API 完全一致)
val processed = inputStream
  .selectExpr("CAST(value AS STRING) as text")
  .withColumn("words", split($"text", " "))
  .groupBy($"words")
  .count()

// 3. 定义输出接收器(Sink)
val query = processed.writeStream
  .outputMode("complete")  // 输出模式
  .format("console")       // 输出位置
  .option("checkpointLocation", "/path/to/checkpoint") // 容错必需
  .start()

query.awaitTermination()

三、关键组件详解
1. 输入源(Sources)
类型描述是否容错
File Source监控目录下的新文件(CSV/JSON/Parquet)
Kafka Source从 Kafka 读取数据(0.10+)
Socket Source测试用(从 Socket 读文本)
Rate Source生成测试数据(固定速率)
2. 输出接收器(Sinks)
类型描述
Console Sink控制台输出(调试用)
File Sink写入文件(Parquet/CSV)
Kafka Sink输出到 Kafka Topic
Foreach Sink自定义写入逻辑(如 JDBC/NoSQL)
Memory Sink结果存入内存表(供 spark.sql 查询)
3. 输出模式(Output Modes)
模式适用场景要求
Append只追加新结果(默认)查询不包含聚合
Update输出变化的行(类似 CDC)支持聚合+Watermark
Complete全量输出结果(每次触发更新整个结果表)需存储全量状态(如聚合)

四、时间概念与窗口操作
1. 时间类型
  • 事件时间(Event Time):数据自带的时间戳(timestamp 类型列)
  • 处理时间(Processing Time):数据到达 Spark 的时间
2. 水印(Watermark)

处理延迟数据的核心机制:

val withEventTime = inputStream
  .withColumn("eventTime", $"timestamp".cast("timestamp"))

val watermarked = withEventTime
  .withWatermark("eventTime", "10 minutes")  // 最大延迟时间
3. 窗口聚合(Tumbling/Sliding)
import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions.Window

// 滚动窗口(5分钟)
val tumblingWindow = watermarked
  .groupBy(
    window($"eventTime", "5 minutes"), 
    $"deviceId"
  )
  .count()

// 滑动窗口(10分钟窗口,5分钟滑动)
val slidingWindow = watermarked
  .groupBy(
    window($"eventTime", "10 minutes", "5 minutes"),
    $"deviceId"
  )
  .avg("value")

五、容错与检查点
  1. 检查点目录(Checkpoint)

    • 存储 source 偏移量
    • 保存聚合查询的中间状态
    • 必需设置:.option("checkpointLocation", "/path")
  2. 恢复流程

    重启时 → 读取检查点 → 恢复偏移量 → 重建状态 → 继续处理
    

六、事件时间处理示例
// 定义 Schema(事件时间字段)
case class Event(deviceId: String, timestamp: Long, value: Double)

// 从 Kafka 读取
val events = spark.readStream
  .format("kafka")
  .option(...)
  .load()
  .select(from_json($"value".cast("string"), schema).as[Event])

// 启用水印 + 窗口聚合
val results = events
  .withWatermark("timestamp", "1 hour")  // 允许1小时延迟
  .groupBy(
    window($"timestamp", "15 minutes"), 
    $"deviceId"
  )
  .agg(avg("value").as("avg_value"))

// 输出到 Kafka
results.writeStream
  .format("kafka")
  .outputMode("update")  // 只输出变化行
  .option("topic", "output-topic")
  .option("checkpointLocation", "/checkpoint")
  .start()

七、性能优化技巧
  1. 触发间隔(Trigger)

    .trigger(Trigger.ProcessingTime("30 seconds")) // 固定间隔
    .trigger(Trigger.Once())                      // 类似批处理
    .trigger(Trigger.Continuous("1 second"))       // 低延迟模式(实验性)
    
  2. 状态管理

    • 使用水印清除旧状态
    • 避免无限状态(如无界 GroupBy)
  3. 水位敏感参数

    spark.conf.set("spark.sql.shuffle.partitions", "200") // 调大 shuffle 并行度
    

八、与 Spark Streaming(DStream)对比
特性Structured StreamingSpark Streaming (DStream)
编程模型声明式 (DataFrame API)过程式 (RDD 操作)
API 一致性与批处理完全统一单独 API
事件时间支持原生支持需手动实现
延迟毫秒~秒级秒级
端到端精确一次原生支持需手动实现
动态表语义

最佳实践

  1. 始终设置检查点以实现容错
  2. 优先选择事件时间而非处理时间
  3. 合理配置水印平衡延迟与状态大小
  4. 生产环境推荐 Kafka → Structured Streaming → Kafka/Delta Lake 架构

通过 Structured Streaming,Spark 实现了 “批流一体” ,允许开发者用同一套代码处理实时流和离线批数据,大幅简化流处理系统的开发和维护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值