一:窗口简述
Flink是一种流式计算引擎,主要是来处理无界数据流的,数据源源不断、无穷无尽。想要更加方便高效地处理无界流,一种方式就是将无限数据切割成有限的“数据块”进行处理,这就是所谓的“窗口”(Window)。 【把窗口理解成一个“桶”,Flink则可以把流切割成大小有限的“储存桶”,把数据分发到不同的桶里,每一个窗口都是一个桶。当窗口结束,就对每一个桶的数据进行收集处理】
二: 窗口的分类
1)按照驱动类型分
(1) 时间窗口
原理:建立一个窗口,在固定的额时间段内不断收集数据,到达结束时间的时候窗口结束收集数据,生成结果,窗口销毁。【就像地铁一样,间隔一段时间发车,无论车上有多少乘客,地铁都会往前开】
(2) 计数窗口
原理:计数窗口基于元素的个数来截取数据,到达固定的个数时就触发计算并关闭窗口。每个窗口截取数据的个数,就是窗口的大小。基本思路是“人齐发车”
2)按照窗口分配数据的规则分类(以下均为以时间驱动为例)
主要概念:窗口的大小,窗口的滑动步长【两个窗口重叠的部分】,会话间隔
(1) 滚动窗口(Tumbling Windows)
滚动窗口有固定的大小,而且窗口之间不会重叠,每个数据都在一个窗口且只属于这个窗口。在一个固定时间内,接受数据的传入。到了截止时间,收集数据,输出结果。应用类型广泛,可以对每个时间做聚合统计。
(2) 滑动窗口 (Sliding Windows)
当窗口大小大于窗口步长的时候就会出现滑动,滑动窗口会重叠,同时数据也会同时被分到多个窗口,滑动步长就代表了计算频率。适合计算结果更新较快的场景。
(3) 会话窗口 (Session Windows)
原理:基于“会话”来进行数据分组、如果相邻两个数据到来的时间间隔 小于指定大小,那么这两个数据在同一个窗口内。如果 大于则数据到了新的窗口,且前面的窗口关闭。 会话窗口长度,起始结束时间不确定。各个分区之间窗口没有任何关联。在规定的时间内没有数据到来触发一次计算。可以用于保持会话的场景下。
(4) 全局窗口 (Global Windows)
把相同key的数据全部分配到一个窗口之中,窗口没有结束是不会触发计算的。如果希望对数据处理,需要定义一个触发器。
三:窗口API
1)按键分区(Keyed)和非按键分区(Non-Keyed)
(1)按键分区窗口(Keyed Windows)
经过按键分区keyBy操作后,数据流会按照key被分为多条逻辑流(logical streams),这就是KeyedStream。基于KeyedStream进行窗口操作时,窗口计算会在多个并行子任务上同时执行。相同key的数据会被发送到同一个并行子任务,而窗口操作会基于每个key进行单独的处理。所以可以认为,每个key上都定义了一组窗口,各自独立地进行统计计算。
在代码实现上,我们需要先对DataStream调用.keyBy()进行按键分区,然后再调用.window()定义窗口。
stream.keyBy(...) .window(...)
(2)非按键分区(Non-Keyed Windows)
如果没有进行keyBy,那么原始的DataStream就不会分成多条逻辑流。这时窗口逻辑只能在一个任务(task)上执行,就相当于并行度变成了1。setParallelism(1)
在代码中,直接基于DataStream调用.windowAll()定义窗口。
stream.windowAll(...)
注意:对于非按键分区的窗口操作,手动调大窗口算子的并行度也是无效的
四:窗口分配器
1)Flink中的时间语义
到底是以哪种时间作为衡量的标准,就被成为“时间语义”
2)时间窗口分配器
(1) 处理时间的时间语义窗口
特征:
- 基于处理节点的当前系统时间。
- 实现简单,延迟低。
- 适用于数据实时性要求高且乱序不多的场景。
- 在处理乱序数据时,结果可能不准确。
应用场景:
- 监控系统指标(如CPU使用率、内存使用情况)。
- 实时数据分析,延迟比准确性更重要的场景。
使用参数:
TumblingProcessingTimeWindows.of(Time.) 滚动窗口 SlidingProcessingTimeWindows.of(Time.) 滑动窗口 ProcessingTimeSessionWindows.withGap() ProcessingTimeSessionWindows.withDynamicGap() 会话窗口
(2) 处理事件的时间语义窗口
特征:
- 基于事件的时间戳。
- 处理乱序数据,通过Watermark机制来处理延迟事件。
- 更加准确,适用于要求严格时间语义的场景。
实时场景:
- 实时日志分析(如用户行为分析、点击流分析)。
- 需要严格时间顺序和准确性的场景,如金融交易分析。
使用参数:
TumblingEventTimeWindows.of(Time.) 滚动窗口 SlidingEventTimeWindows.of(Time.) 滑动窗口 EventTimeSessionWindows.withGap()
EventTimeSessionWindows.withDynamicGap()
会话窗口
3)计数窗口分配器
countWindow(5) | 计数窗口分配器 【滚动】 满足5条输出一次计算结果 |
countWindow(5,2) | 计数窗口分配器 【滑动】 满足5条输出一次计算结果 , 每经过一个步长都有一个窗口-触发输出【第一次输出在第二条数据来的时候】 |
4)全局窗口分配器
GlobalWindows.create() |