Spark Structured Streaming 如何处理迟到数据和状态清理?
本文目录
面试怎么回答
Structured Streaming 的 Watermark 通常是已观测最大事件时间减去迟到阈值,不是系统时间。窗口结束时间落到 Watermark 之前后,Spark 才能清理对应状态并把更晚数据视为过期。状态是否可清理还取决于算子:流流 Join 需要时间范围,任意状态 API 有自己的超时语义。排查时要看 Watermark 是否推进、状态行数和删除指标。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
Watermark 已经配置,State Store 却还在持续变大。
常见原因是把“允许迟到多久”当成了一个定时删除器,却没有看事件时间列、算子语义和 Watermark 是否真的向前推进。
Watermark 根据已观测最大事件时间减去迟到阈值推进;只有算子能证明旧状态不再影响未来结果时,才会清理状态并丢弃过晚数据。
Watermark 不是当前系统时间
它通常由查询已看到的最大事件时间减去延迟阈值得到。若上游长时间没有新事件时间、某个输入流落后,或事件时间字段解析错误,Watermark 就不会按墙上时钟持续前进。判断问题要看 StreamingQueryProgress 中的 eventTime 指标。
窗口聚合如何判断状态过期
对结束时间为 T 的窗口,只有 Watermark 超过 T,Spark 才能认定允许范围内的迟到数据不会再改变它。Update 模式会在期间持续修正,Append 模式通常等窗口最终关闭后输出。超过 Watermark 的极迟记录可能被丢弃。

阈值是在正确性和资源之间取舍
阈值越大,能接纳更晚的数据,但状态保留更久、磁盘和检查点成本更高;阈值越小,资源更可控,却会丢失更多晚到事件。应基于真实延迟分布、业务可补偿方式和结果时效要求确定,而不是统一写一个 24 小时。
不是所有状态算子都同样清理
窗口聚合、去重、流流 Join 和任意状态 API 的清理条件不同。Watermark 必须作用在正确的事件时间列,并进入算子需要的位置;例如流流 Join 还需要时间范围条件,才能推导某侧旧状态何时不再匹配。仅调用 withWatermark 并不保证所有状态自动有界。

多输入 Watermark 还要关注慢流
多流查询通常需要组合各输入的 Watermark。默认安全策略可能受最慢输入约束,避免误删状态;如果采用更激进策略,能降低延迟和状态,却可能丢掉慢流数据。设计时要区分真正迟到、上游停流和分区长时间空闲。
排查 State Store 增长的顺序
先看输入事件时间最大值和 Watermark 是否推进,再看状态行数、删除行数和内存或磁盘大小;确认窗口或 Join 时间条件能否推导过期;最后检查极端 Key、空闲流和 Checkpoint 状态版本。不要一上来只调小阈值。