00:00
我们已经了解了flink当中水位线的概念、原理和传递规则,而且我们知道了在代码当中怎么样去生成水位线啊,但是我们会发现啊,前面所写的代码都只是创建了水位线的生成策略,我们并没有办法看到它最终的效果。那水位线最终是用来干什么的呢?啊,当然是要控制我们当前的事件时间,那就是跟事件时间有关的一些操作就会通过水位线的推进来体现出来,那这里边最典型最经典的一个应用当然就是窗口了,时间窗口,所以接下来呢,我们要介绍的就是窗口这一部分内容。其实啊,窗口这个概念我们并不陌生,而且它其实是我们在做大数据处理的时候非常重要的一种手段啊,我们前面介绍的这个基本API大家会发现啊,Map flat map基本转换算子,还有像reduce这样的聚合算子,它其实做的操作是什么呢?都是每来一个数据就做一次转换,做一次聚合,做一个计算,然后就会输出对应的一个结果,每来一个就做一次计算,输出一个结果。
01:12
那这样的话,假如说啊,我们统计就是word count吧,我们统计当前的个数。数据无休无止的来,对于无界流而言,我们最终统计的其实就是所有数据的每一个word对应的count值,它出现的频次,哎,那这就相当于是全量数据统计嘛,一个历史数据的统计。但是在真实的应用场景里边呢?我们最关心的往往并不是整个无限流的历史数据。当然了,有些指标可能我们要统计所有的历史数据啊,但是更多场景下,我们关心的是最近一段时间发生的所有事件,收集到的所有数据啊,比如说我们统计PVUV啊,那往往可能我们想要看的啊,是像日活月活这样的一些信息,我们统计的是每一天用户的访问量,每个月用户的访问量下的订单量,他们都是按照一段时间去进行数据的收集和处理的,哎,所以我们看到这种处理方式呢,就相当于在无界流上打开了一个窗口,截取了一段有限的数据进行聚合分析统计。
02:25
这就是我们所说的窗口操作。所以简单来讲,对于flink来说,它本身要处理的是无界流,那窗口呢,其实就是让我们把无界流转换成某种意义上的有界流去进行具体分析的一种手段啊,那所以在link当中窗口API啊,其实非常丰富的窗口是一个非常重要的数据流处理的操作。所以接下来呢,我们来详细的讲解一下flink当中窗口到底是什么啊,其实我们会觉得这个窗口太简单了啊,其他的一些大数据处理工具,甚至像skyla这个语言里边啊,我们进行集合处理操作的时候,都有类似于窗口的概念。
03:09
简单来说,诶,对于我们这里的一组数据,那其实就是打开一个窗口,就像一个框一样,把一部分数据框在里边,这就是属于某一个窗口,比如说啊,我们按照这个这里边的数字啊,数据里边带的数字都是一个时间戳单位,比如说就是秒,那么我们零到十秒开一个窗口,诶这样的话,只要在十秒之前的数据就都分配到了这个窗口内,那十到20秒下一个窗口,诶那么接下来后边的数据就都收到了这个窗口内,再接下来当然就是20~30秒,哎,我们看到这其实就是每隔十秒开一个窗口嘛,数据就分别分配到了不同的窗口当中。这里我们发现就是一般定义窗口的时候就是说的啊,都是左闭右开,包含零就不包含十,这样的话下一个窗口就可以包含十了,每一个数据它只会包含在一个窗口当中,当然了在有些场景下,窗口也可以有重叠的,那就是我们后面会讲到滑动窗口。
04:11
他每一次可能都移动的不是整个我们窗口的长度,每一次移动一部分,那他们之间就会有重叠部分了。这样理解确实看起来非常的简单,我们就把窗口当成一个框就可以了,但是呢,对于事件时间与意向乱序数据出现的时候,我们就会发现这样处理就会有问题了,诶,我们看到啊,当前零到十秒这个窗口当中收集到的确实都是十秒之前的数据,但是呢。十到20秒,这个窗口里边就有一个九秒钟的数据跑到了这里,这就是我们说的乱序流,里边有些数据它会迟到,那如果要是迟到数据,他所属于的那个窗口已经关闭了,他就只好落到下一个窗口里面去进行统计了,这就会导致我们的统计结果出现偏差,不够准确。
05:03
怎么解决这个问题呢?诶,那我们自然想到了,之前不是说了这个乱序流里边我们应该设置一个延迟时间吗?诶,那就相当于我们要多等一会儿延迟发车,你前面那个窗口不要那么快的关闭,这样的话我们就变成了比方说在这个流里边,我们看到最大乱序程度差不多是两秒钟啊,11秒后面有九秒的数据,那我们就设置一个两秒钟的延迟,这样的话那就需要等到12秒这个数据来的时候。Water才会进展到十。这个时候。视线时间到十秒了,那么我们就关闭零到十秒的这个窗口。这个时候我们看到,诶,没有问题,那所有的十秒之前的数据都收进来了,但是又涉及到另外一个问题,就是既然数据是乱序,那有迟到的数据,那就有在他之前已经到来的属于下一个窗口的数据啊,比如说这里的十一十二。他们本来应该属于十到20秒窗口。
06:03
但是现在如果我们多等一会儿的话,那他们岂不是就要被收到零到十秒这个窗口里边来了吗?怎么解决这个问题呢?其实我们联系一下平常赶班车的这种场景,我们就会想到啊,一般情况我们去赶班车的时候,哎,那当然就是有哪一辆车,哎,我们既然来了之后啊,这辆车停在那里,那我们就直接上就完了嘛,一般都是一班车发走了之后,才会有下一班车开始开放啊,让人上去,但是我们会想到就是如果说我们现在限定了某一个人,某一个数据,他只能上下一班车,不能上当前的这一班车。诶,那怎么样呢?那就当前这一班车尽管还没发,你就不要上这班车嘛,你就直接等着,或者说下一班车有可能已经开门了,你就直接上下一班车不就完了吗。诶,所以我们想到了啊,在真正的处理场景里边,窗口并不是说零到十秒和十到20秒的窗口只能有一个,他们就像两班车一样,完全可以同时的停在这里,等待对应的人上车,所以呢,诶,我们在这里边不应该把这个窗口看成一个框,我们可以把它看成一个班车,或者说看成一个桶,收集对应时间戳数据的桶。
07:19
这样的话,他们就可以同时存在,同时放在这里了。那接下来就是我们判断当前的数据时间戳符合某个桶的收集范围的话,那就直接把它扔到对应的桶里面去,如果有提前来了的数据,诶,那就把它扔到对应的下一班车,也就是下一个桶里边就可以了嘛,啊那至于我们当前事件进行进展的时候呢,要关闭哪个窗口,那就把对应的那个桶里边的所有数据拿出来,去进行一个计算处理,输出结果就可以了。啊,所以接下来我们可以按照这个例子啊,再完整的梳理一下,到底应该怎么做窗口的计算,哎,那就是首先二这个数据来了,哎,那我们当前就把它扔到零到十秒的这个窗口里面来,这个桶里面来,五来了啊,扔到这里来,后边9789,所有数据来了之后,都会放到当前的第一个窗口里面来,然后接下来11来了,11来了怎么办呢?诶,十一来的时候我们知道啊,当前假如后边有water mark的话,周期性生成了一个water的话,延迟两秒钟,当前的时间只进展到九,所以零到十秒这个窗口是不关的。
08:29
那11他也得放到对应的一个窗口里啊,它不能放到这个窗口,它要放到。十到20秒的这个窗口里来啊,就这几班车都等在这儿了,你该上哪个车上哪个车啊,同样后边九这个数据又来了,那同样接下来他还可以这迟到数据嘛,呃,那没关系,我们等着他呢,等的就是它,所以它直接进入到第一个窗口,零到十秒这个窗口来,接下来12又来了,12来了之后呢,同样它是属于下一班车的,它也要进入十到20秒这个窗口,12来了之后,现在的water。
09:03
我们延迟两秒钟water mark进展到了十,那我们发现遇到了十秒的water mark,那就要处理十秒钟要发生的对应的一些时间上的操作,那我们要干什么呢?当然就是关闭零到十秒的窗口,所以这个时候我们把这个桶里边收集到的所有数据拿出来做一个统计,计算输出结果。啊,当然了,做完操作之后,这个桶就可以直接关掉窗口,就可以关掉了,桶就可以销毁掉了,就可以回收了,诶那再接下来15来了之后,他进第二个窗口,14进第二个窗口20啊20我们知道前闭后开嘛,20是属于第三个窗口的,所以二十二十一他们又分别进入到了第三个窗口啊19是迟到数据,它同样进第二个窗口。这个时候呢,我们的最大时间戳只是21,当前的watermark只有19,所以第二个窗口还不关,等到22来了之后,他自己要进入到第三个窗口,而当前的时间戳最大时间戳是22,所以watermark就进展到了20,那这个时候就会触发第二个窗口的处理计算,把所有的数据收集齐了,计算得到结果传递到下游,然后这个窗口就可以关闭销毁了。
10:21
那接下来就是第三个窗口计算,所以这就是整个窗口计算的完整过程。我们这里需要明确的一点就是窗口并不是。有了零到十秒的窗口,就不能有十到20秒的窗口,他们完全可以同时存在,那数据呢,只要判断自己的时间戳他该属于哪个窗口,就进入到哪个桶里边去进行计算就可以了啊,那对应的就是窗口什么时候开,什么时候关呢?诶注意啊,这个窗口并不是一开始就都已经放在这里,没有必要这个浪费系统资源嘛,它是只有在属于自己时间范围内的那个数据来了之后,有第一个数据来了之后,才会触发当前窗口的创建。
11:08
好,然后接下来就是收集数据,那窗口什么时候关闭呢?那就是我们说的,当水位线进展到了当前窗口的结束时间的时候,那就会触发当前窗口的计算,把收集齐的数据进行一个统计,计算得到结果输出到下游,然后关闭当前的窗口。所以本质上来讲,窗口的触发计算和窗口最后的关闭,这是两个行为啊,但是一般情况下我们可以把它等同对待啊,因为我们知道就是到了结束时间点的时候做这个操作嘛,它是有先后顺序的啊,先做计算,最后再关闭,后面我们会讲到,其实这两个行为也可以完全分开,我们讲到的时候会给大家再重复的介绍这些概念。这就是关于窗口操作的基本概念。
我来说两句