Apache Spark 第 8 章:Structured Streaming 流处理

好,第八章深入拆解 Structured Streaming,从设计哲学开始,逐层剖析。

  • 先看第一张:流处理核心模型。核心模型清楚了。
  • 接下来看微批次的执行引擎内部------每次触发时 Spark 到底做了什么:微批次执行机制和容错原理搞清楚了。
  • 接下来是最难理解的部分------Watermark 事件时间处理:Watermark 和时间窗口搞透了。
  • 接下来看 State Store 的工作机制和 Streaming 完整的读写体系:四张图把第八章完整覆盖。

下面是核心知识梳理:


核心模型(第一张) 是 Structured Streaming 最革命性的设计思想:把流抽象成一张不断追加行的无界表 。这意味着你写的代码和批处理完全一样------df.filter(...).groupBy(...).agg(...) 这套 API,批处理里能用,流处理里也能用,引擎自动把它转成增量计算。三种 Output Mode 控制每次触发后输出什么:Append 只追加新行(适合无状态或带 Watermark 的聚合),Complete 每次输出全量(全局聚合时用),Update 只输出变更行(最节省网络)。四种触发器则控制多久处理一次:ProcessingTime 固定间隔最常用,AvailableNow 用于一次性批量处理历史数据,ContinuousReal-Time Mode 则是追求毫秒级延迟的选项。


微批次执行周期(第二张) 是 Exactly-Once 的实现基础。每次触发分四步:查询 Source 最新 Offset → 写 WAL 日志(预先记录本批 Offset 范围)→ 执行批处理(读新数据、转换、更新 State Store)→ 写 commit 文件(确认本批完成)。Checkpoint 目录是整个容错机制的核心,offsets/ 记录每批的 Offset 范围,commits/ 记录哪些批次已完成,state/ 存储有状态算子的中间数据。恢复时的逻辑很直接:有 offset 没有 commit 说明上次失败了,重跑这批;两者都有说明已完成,跳过。


Watermark 与事件时间(第三张) 解决的是现实流处理的核心难题:网络延迟导致数据乱序到达。withWatermark("timestamp", "10 minutes") 告诉 Spark 允许最多 10 分钟的乱序延迟------Watermark 等于当前最大事件时间减去容忍值。事件时间落在 Watermark 之后的数据正常处理,落在 Watermark 之前的数据被直接丢弃。三种窗口类型的选择很清晰:滚动窗口用于每N分钟统计一次,滑动窗口用于"最近N分钟"类的实时指标,会话窗口用于用户行为分析(按活动间隙切割 Session)。


State Store 和读写体系(第四张) 是生产部署的关键。State Store 是有状态计算的存储引擎,默认的 HDFSBackedStateStore 状态存内存,适合中小状态;生产环境强烈推荐换成 RocksDBStateStore(Spark 3.2+),状态存本地磁盘,完全绕过 JVM GC,支持 TB 级超大状态,增量 Checkpoint 速度也更快。Source 端 Kafka 是生产首选,支持 Offset 回放保证 Exactly-Once;Sink 端推荐 Delta Lake,事务写入天然支持 Exactly-Once,其次是 File Sink。自定义 Sink 用 foreachBatch(推荐,批量写效率高)或 foreach(逐行,灵活但慢)。


最后附一段完整的生产级代码示例:

python 复制代码
from pyspark.sql import SparkSession
from pyspark.sql.functions import window, count, col, from_json
from pyspark.sql.types import StructType, StringType, TimestampType

spark = SparkSession.builder \
    .config("spark.sql.streaming.stateStore.providerClass",
            "org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider") \
    .getOrCreate()

schema = StructType() \
    .add("user_id", StringType()) \
    .add("city", StringType()) \
    .add("event_time", TimestampType())

# 读取 Kafka
df = spark.readStream \
    .format("kafka") \
    .option("kafka.bootstrap.servers", "broker:9092") \
    .option("subscribe", "orders") \
    .option("startingOffsets", "latest") \
    .load() \
    .select(from_json(col("value").cast("string"), schema).alias("d")) \
    .select("d.*")

# 带 Watermark 的滑动窗口聚合
result = df \
    .withWatermark("event_time", "10 minutes") \
    .groupBy(window("event_time", "10 minutes", "5 minutes"), "city") \
    .agg(count("*").alias("order_count"))

# 写入 Delta Lake(Exactly-Once)
query = result.writeStream \
    .format("delta") \
    .option("checkpointLocation", "s3://bucket/checkpoints/orders/") \
    .outputMode("append") \
    .trigger(processingTime="1 minute") \
    .start("s3://bucket/delta/order_stats/")

query.awaitTermination()
相关推荐
tedcloud1232 小时前
Wand-Enhancer 怎么搭建?开源 Wand 客户端增强与远程控制工具介绍
大数据·服务器·人工智能·开源·音视频
大大大大晴天4 小时前
每天认识一个组件:分布式缓存Alluxio
大数据
AI_Auto5 小时前
架构视角看数字化转型|核心架构:大共享平台+小应用,从按需走向适变
大数据·人工智能·架构·制造
小蒋观天下5 小时前
社区AI智能摄像头完整选型指南
大数据·人工智能·安全·计算机视觉·语音识别·ai大模型
AI 思录5 小时前
Prompt 事故档案(八):日常表达被标为“待校准”,AI 的爹味语法从哪里来
大数据·人工智能·算法·prompt·用户体验·ai合规
2601_965742227 小时前
全媒体运营与短视频代运营,两者有什么区别?
大数据·数据结构·人工智能·算法·ai·媒体
anxiao_m7 小时前
2026企业AI数字孪生选型攻略,不同场景对应不同解决方案
大数据·网络·数据库
SelectDB8 小时前
从 ClickHouse 迁移到 Doris:SQL 兼容、同步与验证清单(实战笔记)
大数据·数据库·数据分析
SelectDB8 小时前
Doris 还是 ClickHouse?一张表说清 6 个关键差异(实战笔记)
大数据·数据库·数据分析
DolphinScheduler社区8 小时前
Apache DolphinScheduler 8 月报:权限安全加固,调度补火上线,性能与稳定性持续提升
大数据·安全·开源·apache·任务调度·海豚调度