Flink怎么去控制window
window分类
Flink的DataStream API提供了基于Count Window,Time Window和Session Window。三者其实就是计算的单位不同,
TimeWindow
TimeWindow是基于时间的,能够在一定时间内,收集到一定的数据,从而触发Window的操作。常见的有Sliding Time Window和Tumbling Time Window
👌Sliding Time Window
中文翻译过来就是滑动时间窗口。它在Flink里面需要两个参数,就是每个多久计算多大Window的事件。下面这个图sliding size是2也就是每隔多久,而window size是窗口Window大小,从而理解长每个2个事件单位就生成一个窗口,每个窗口大小为3个时间单位,因为2<3,所以就会有重复计算的某个时间点的内容,这主要是因为滑动窗口它滑过去的时候会有重叠的内容
.timeWindow(Time.seconds(2),Time.seconds(1))
//这个就是每隔1秒,生成一个2秒大小的window
👌Tumbling Time Window
中文翻译过来就是滚动时间窗口,这个是滚动的,我们平常用轮子去滚动地面的时候,是不会有重复经过的路的,它一定是一直往前的。那么Tumbling Time Window就是基于时间滚动,它是需要知道窗口Window的size,也就是接受一个size参数,每次创建窗口都是基于上次窗口的末端而作为本次窗口的起始。很多人就会想到Sliding Time Window如果每隔x个时间单位,计算x大小的窗口不就是和Tumbling Time Window一样的吗,也可以这么理解吧。下面这个图,可以看到将时间等分了。
.timeWindow(Time.seconds(10))
//这个就是每次创建10秒大小的窗口
Count Window
Count Window是基于计数的,也就是当计数达到规定要求时,就会触发Window操作,就是如果对于Time Window的数据进入数据速度均匀的话,其实和计数达到的效果是一样的,但是我们还是要加以区分
Sliding Count Window
只要看到Sliding Window,我们就要知道它是基于滑动的。图找不到
data.keyBy(1)
.countWindow(100, 10) //每 10 个元素统计过去 100 个元素的数量之和
Tumbling Count Window
这个就是Tumbling Window,基于滚动的。就是每次个size个事件之后创建一个窗口
Session Window
session Window显然就是基于会话,如果session断了,那么就要触发window操作了。
Window的组件和相互关系
window Assigner
用于将某个元素分配到某个窗口里面去。
window本身只有一个标识符ID,Window中的元素存储在了Key/Value State中,关于State也是非常重要的内容。
Window Trigger
用于决定一个窗口什么时候被执行,或者什么时候被清除掉
每当有元素加入到这个窗口,或者之前注册的定时器超时,就会触发操作。返回的结果有好几种continue:不做任何操作,fire:开火,即处理窗口数据,purge:移除窗口和窗口中的数据。但是仅仅是fire的话,就会导致处理完当前窗口的数据后,其数据还留在那里,下一次处理还是在那里,甚至有些逻辑我们会重复计算,当然这只是存在于我们自定义Trigger的情况,像Flink本身有的sum,max这些算子,它只需要每来一个元素就清除一次,这样我当前窗口还是保持这sum,max算子的逻辑,而计算过的元素就不需要了,这样可以减少内存消耗。
Evictors
中文翻译成“驱逐者”,有点类似于filter,就是窗口操作前将window里面不合格或者不需要的元素剔除掉
看看图吧👉
一个元素来了,那么就由Window Assigner来分配到哪个窗口,如果达到新创建窗口标准那么就新建窗口然后分配进去
分配到窗口后,就需要将元素insert进入,如果达到了Trigger的条件了,那么久触发window操作
在Window操作之前,我们需要经过Evictor的过滤,也就是经由Evictor Function处理后,才将流交由各种窗口函数处理
针对上面的Time,我们需要这个Time是以什么为标准,是事件生成的时间(比如日志有个时间戳),还是进入Flink的时间,或是当处理这个事件的时间呢,根据这个Time分为了好几个:见下图
-
Window Processing Time: 处理时间:处理时间是指执行相应操作的机器的系统时间。
当流程序在处理时间上运行时,所有基于时间的操作(如时间窗口)都将使用运行相应操作员的计算机的系统时钟。每小时处理时间窗口将包括系统时钟指示整小时之间到达特定操作员的所有记录。例如,如果应用程序在上午9:15开始运行,则第一个小时处理时间窗口将包括上午9:15到上午10:00之间处理的事件,下一个窗口将包括上午10:00到上午11:00之间处理的事件,依此类推。
处理时间是最简单的时间概念,不需要流和机器之间的协调。它提供最好的性能和最低的延迟。但是,在分布式和异步环境中,处理时间不提供确定性,因为它易受记录到达系统的速度(例如从消息队列)和记录在系统内的操作员之间流动的速度以及中断(计划的或其他的)的影响。 -
Event Time: 事件时间是每个事件在其生产设备上发生的时间。该时间通常在它们进入Flink之前嵌入记录中,并且 可以从每个记录中提取事件时间戳。在事件时间中,时间的进度取决于数据,而不取决于任何挂钟。事件时间程序必须指定如何生成“ 事件时间WaterMark”,这是一种表示事件时间进展的机制。
在理想情况下,事件时间处理将产生完全一致且确定的结果,而不管事件何时到达或它们的顺序如何。但是,除非已知事件是按时间戳(按时间戳记)到达的,否则事件时间处理会在等待无序事件时产生一些延迟。由于只能等待有限的时间,因此这限制了确定性事件时间应用程序的可使用性。 -
Ingestion Time: 俗称摄取时间,就是进入Flink的时间,在Flink 最开始的Source处的时间,它介于Event Time和Window Process Time之间。可以自动维护WaterMark,不用自己维护
代码设置Time类型
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//处理时间
env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
//进入Flink的摄取时间
env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime);
//真正意义上的事件发生的时间
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);