Flink 窗口怎么选?滚动、滑动、会话有什么区别?
面试怎么回答
滚动窗口固定且不重叠,适合按分钟、小时做周期统计;滑动窗口由大小和步长决定,会重叠,适合持续观察最近一段时间,但要关注一条数据进入多个窗口带来的状态和计算成本;会话窗口按不活跃间隔动态切分,适合用户访问这类没有固定边界的过程。实际选择时,我还会明确 Event Time、Watermark、分组 Key、迟到数据和聚合方式,而不是只比较三个定义。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
很多人会回答:
“滚动窗口不重叠,滑动窗口会重叠,会话窗口按用户活跃间隔切分。”
定义没错,但还不够。
面试官真正想听的是:
你能不能从业务问题、输出频率、时间语义和状态成本出发,选出合适的窗口。
第一步:滚动窗口适合固定周期统计
滚动窗口有固定大小,相邻窗口之间不重叠,一条数据只属于一个窗口。
例如每 5 分钟统计一次订单量:
[10:00, 10:05)
[10:05, 10:10)
[10:10, 10:15)
它适合固定报表、定时告警、每小时或每天汇总等场景。
优点是语义清晰、状态和计算成本相对可控;缺点是窗口边界很明显,无法直接回答“任意时刻最近 30 分钟”的问题。
第二步:滑动窗口适合持续观察最近一段时间
滑动窗口由两个参数决定:窗口大小和滑动步长。
例如“每 1 分钟计算最近 10 分钟的请求量”:
窗口大小:10 分钟
滑动步长:1 分钟
窗口之间会重叠,同一条数据可能进入多个窗口。
它适合实时趋势、滚动指标和连续告警,但代价也更高。窗口大小是 24 小时、步长是 1 分钟时,一条数据理论上可能参与约 1440 个窗口的计算。
所以滑动窗口不能只看业务效果,还要评估:
- 窗口大小与步长的比例
- 状态量和输出频率
- 是否使用增量聚合,而不是把所有明细都攒到窗口结束
- 业务是否真的需要这么高的刷新频率
第三步:会话窗口适合没有固定边界的行为过程
会话窗口没有固定长度,而是根据“不活跃间隔”判断会话是否结束。
例如设置 30 分钟 Session Gap:同一用户持续产生行为时,会话不断延长;超过 30 分钟没有新事件,当前会话才关闭。
它适合用户访问、设备连接、游戏对局等自然会话场景。
但它也更依赖数据质量和时间语义。迟到事件可能让两个原本分开的会话重新合并,状态管理和结果更新会更复杂。

第四步:选完窗口类型,还要回答四个问题
窗口类型只是第一层,生产设计里还要继续确认:
1. 用 Event Time 还是 Processing Time?
如果统计要反映事件真实发生时间,通常优先考虑 Event Time,并设计 Watermark 和迟到数据策略;如果只关心系统当前处理速度,Processing Time 更简单,但结果会受延迟和重启影响。
2. 按什么 Key 分组?
窗口通常应该在 keyBy 后执行,让不同 Key 并行计算。直接使用 windowAll 会把数据汇总到单个并行实例,容易形成性能瓶颈。
3. 什么时候触发、迟到多久还能更新?
要明确 Trigger、Allowed Lateness 和 Side Output,否则迟到数据到底丢弃、补算还是更新旧结果,口径会不一致。
4. 窗口里保存明细还是增量结果?
能用 ReduceFunction 或 AggregateFunction 增量聚合,就尽量不要等窗口结束后再一次性遍历全部明细。
一个典型场景
比如业务要“每分钟展示最近 24 小时 UV”,直接设计 24 小时大小、1 分钟步长的滑动窗口。
需求看起来合理,但窗口重叠比例非常高。如果每条事件被重复分配到大量窗口,并在窗口里保存完整明细,状态、Checkpoint 和输出压力都会快速上升。
这时不能只说“把并行度调大”。应该重新评估一分钟刷新是否必要,并结合增量聚合、分层预聚合或更适合的去重状态方案降低重复计算。
窗口不是时间参数配置题,而是业务实时性、结果准确性和资源成本的取舍题。