Flink 中的 Window 分为哪几类?
在 Apache Flink 中,Window(窗口)是将无限流(Unbounded Stream)切割为有限流(Bounded Stream)的核心机制。
Flink 的窗口分类通常可以从以下 三个维度 进行划分:
1. 按照窗口分配器 (Window Assigner) 分类 —— 最核心的分类
这是最常被问到的分类方式,它决定了数据如何被分配到不同的窗口中。主要分为以下四类:
A. 滚动窗口 (Tumbling Windows)
- 特点:窗口大小固定,窗口之间不重叠,且首尾相接。
- 适用场景:每个数据只属于一个窗口。例如:每 5 分钟统计一次 PV。
- API:
TumblingEventTimeWindows,TumblingProcessingTimeWindows
B. 滑动窗口 (Sliding Windows)
- 特点:窗口大小固定,但窗口之间有重叠。由
Window Size(窗口大小)和Window Slide(滑动步长)两个参数决定。 - 适用场景:需要对最近一段时间内的数据进行频率统计。例如:每 1 分钟统计过去 5 分钟的平均值。
- API:
SlidingEventTimeWindows,SlidingProcessingTimeWindows
C. 会话窗口 (Session Windows)
- 特点:窗口大小不固定。它由“会话间隙”(Session Gap)决定,即如果一段时间内没有接收到新数据,则认为当前会话结束,窗口关闭。
- 适用场景:用户行为分析。例如:统计用户在一个连续活跃期间的操作,如果用户 30 分钟没操作,则视为新会话。
- API:
EventTimeSessionWindows,ProcessingTimeSessionWindows
D. 全局窗口 (Global Windows)
- 特点:将所有相同 Key 的数据分配到同一个巨大的窗口中。这个窗口默认没有结束时间。
- 注意:Global Window 必须配合自定义的 Trigger(触发器) 使用,否则窗口永远不会触发计算(因为默认 Trigger 是 NeverTrigger)。
- 适用场景:需要自定义复杂的触发逻辑(如:每攒够 1000 条数据计算一次,或者遇到特定结束标志才计算)。
- API:
GlobalWindows
2. 按照驱动类型 (Time vs Count) 分类
窗口的触发和划分是基于“时间”还是“数量”?
A. 时间窗口 (Time Window)
- 基于时间范围划分。
- 又细分为:
- Event Time (事件时间):基于数据自带的时间戳。
- Processing Time (处理时间):基于机器系统时间。
B. 计数窗口 (Count Window)
- 基于元素的个数划分。
- 滚动计数窗口:例如每 100 个元素计算一次。
- 滑动计数窗口:例如每收到 10 个元素,计算过去 100 个元素。
- 注:底层其实是 Global Window + CountTrigger 实现的。
3. 按照数据流类型 (Keyed vs Non-Keyed) 分类
这决定了窗口是在并发流上运行,还是在单线程流上运行。
A. Keyed Windows (键控窗口)
- 定义:在
keyBy()操作之后调用的窗口。 - 特点:
stream.keyBy(...).window(...)。 - 并发性:高。不同 Key 的窗口会分布在不同的 Task Slot 中并行计算。
B. Non-Keyed Windows (非键控窗口)
- 定义:直接在 DataStream 上调用
windowAll()。 - 特点:
stream.windowAll(...)。 - 并发性:并行度强制为 1。所有数据都会汇聚到一个 Task 中处理,容易成为性能瓶颈(Data Skew)。
总结图表
| 维度 | 类别 | 描述 | 典型 API |
|---|---|---|---|
| 分配逻辑 | 滚动 (Tumbling) | 固定大小,无重叠 | .window(TumblingEventTimeWindows.of(...)) |
| 滑动 (Sliding) | 固定大小,有重叠 | .window(SlidingEventTimeWindows.of(...)) |
|
| 会话 (Session) | 动态大小,基于间隙 | .window(EventTimeSessionWindows.withGap(...)) |
|
| 全局 (Global) | 单一无限大窗口 | .window(GlobalWindows.create()) |
|
| 驱动方式 | 时间 (Time) | 基于事件或处理时间 | (上述 API 均支持) |
| 计数 (Count) | 基于条数 | .countWindow(size) / .countWindow(size, slide) |
|
| 数据流向 | Keyed | 并行处理 | .keyBy(...).window(...) |
| Non-Keyed | 单点全量处理 | .windowAll(...) |
右滑查看面试常问