00:00
然后接下来我们既然已经知道事件时间语义是什么样子了,那接下来我们就要考虑一个非常重要的情况了,因为之前我们说过啊,因为有这个,呃,网络的这个传输的延迟,那么导致后边我们的数据可能会出现迟到的状态,那迟到本身这个还比较简单,你有延迟的话,我等一会儿不就完了吗?但关键是在于后边我是不是还有这个分布式传输的情况啊,如果出现这个分布式传输,然后分区做这个数据传递,最后是有可能是不是会出现乱序啊,就本身我这个数据是先发生的,但是呢,到后面处理的时候发现它排到后边了。那这种情况在实际使用的过程当中到底应该怎么处理呢?诶大家看一个具体的场景啊,啊大家可能知道我们在这个事件时间语义下啊,如果说我们设置的事件时间语E,那接下来如果说我们有这个窗口操作的话,那大家想以什么为准,比方说我现在有一个五秒钟滚动窗口啊,零到五秒一个窗口,那大家想正常来讲是不是?呃,大家想之前我们在这个看系统时间,看处理时间的话,那就是,呃,我我就看当前系统时间到五秒钟我就关一个窗口,对吧?啊就直接结束了,那现在如果要是事件时间的话,应该什么时候结束这个窗口呢?
01:23
什么时候是五秒钟到了呢?你这个不能看我当前的系统时间了,对吧?那得看什么?对,那大家看,既然是看事件时间,那是不是就应该看当前数据里边带着的那个时间戳啊,诶,所以大家看啊,理想情况下,我当前的这个数据是不是就应该是123456,按照他们发生的顺序,大家看这里边的这个数字就代表它的那个时间戳,自己的那个发生的时间戳,对吧?啊,那接下来理想情况它是按照这个顺序排好的,那我是不是来了第一秒的数据,我就可以认为事件时间现在到一了,到一秒了,来了二秒的数据,是不是现在我实线时间就往前推移了呀,就变成二秒了,对吧?那什么时候关零到五秒的这个窗口呢?
02:10
那大家想是不是我就直接。五秒的数据来了之后,接下来是不是就可以关这个零到五秒的窗口了啊,大家说要注意啊,我这儿是直接把它框画了一个这个时间窗口,直接把它做了一个框框起来了,那有同学可能就想,诶,那不对呀。12345这五个数据都包含在零到五秒之内吗?诶,不是的,呃,大家知道这个零到五秒窗口是包含零不包含五对吧?哎,所以这个五秒是不是不应该属于这个窗口啊?所以大家注意事件时间语义下应该是什么样的一个处理呢?我们之前说窗口是桶对吧,所以接下来大家看啊,给大家画一下当前一个一个数据来,那我当前是不是五秒钟一个窗口,我应该开这样的一个一个桶。
03:02
所以首先是零到五秒。包括零,不包括五。那大家想是不是一来了之后。放进去对吧?哎,然后后边二来了之后是不是也放进去啊,三来了之后也放进去,四来了之后也放进去,而且大家知道这每一个数据来的时候是不是都代表着时间朝前推移啊,就是一来了之后是不是现在是一秒第一秒对吧?啊那个二来了后现在是两秒钟了啊,三来了之三秒钟了,那大家注意五来了之后怎么办呢?对,大家注意五来了之后是不是它应该放到第二个桶里面去啊。五来了之后,代表我们当前啊,这个第二个桶已经有数据来了,这是五到十。所以大家看这个处理的这个过程里边,并不是说我们所有的数据就必须在一个框里边,一个桶里边,你可以同时有好多个桶啊,所以五这个数据是放在这儿的。
04:07
那另外上面这个桶怎么办呢?大家会发现五的到来是不是代表了时间是不是进展到五了,诶那我们判断一下时间进展到五,我有没有要做的操作呢?结果你发现前面这个窗口是不是到五秒就应该要结束,要输出它的结果要关啊,所以接下来是不是五来了之后,它本身是塞到了五到十秒的这个窗口,但是它会引发一个操作,因为时间到五秒了,它是不会引发当前的这个直接输出结果,然后关闭窗口啊。啊,所以大家看这个它的这个对于窗口的控制是分成好几步的,对吧?并不是说我们这里边想象的就只有这么一个框,往这儿一框,然后这个窗口就结束了,不是这样的啊,它是桶,所以说我们现在呃,正常处理的情况其实是这样,那这个也比较简单,就是就是来一个数,然后我就该关什么就关什么,对吧?那这就很简单嘛,然后之后五本身属于五到十的这个窗口,它是不是本身没关啊,所以你接下来是不是继续来对吧?六来了之后继续放这儿,然后你假如有七的话,七来了之后是不是也是继续放这儿啊,那什么时候这个窗口再关呢?
05:21
那是不是等到时来了之后,对吧?而且时还不属于它时是属于下一个窗口对吧?啊,但是时代表时间已经进行到十了,那是不是可以把这个窗口关掉了?那所以理想状态下我们就是来一个处理一个,然后呢,每一个数据都代表着时间的一个推进,那这个数据到底属于哪个窗口,我就把它丢到哪个桶里去,而它代表的那个时间,如果要是已经触发了一个某一个窗口的关闭的话,那是不是我就把对应的那个窗口之间输出结果关掉就可以了?哎,所以本身理想状况状态下,我们事件时间应该这么去用,这个看起来还是很完美对吧?呃,非常简单嘛,你就按照这个时间戳代表我们的时间进展不就完了吗?啊,但是往往现实不尽如人意啊,就是理想很丰满,现实很骨感,那你看我们的这个分布式架构里边数据出现乱序了。
06:18
乱序的话就是代表什么叫乱序,就是事件时间语义下,本来先发生的事件是不是有可能后来了,排到后面去了,对吧?所以大家看这个就只有在事件时间语义下才有意义,对吧?啊,你如果不考虑事件时间,你不考虑它发生的那个时间戳的话,不存在乱序嘛,什么时候来就是什么时候的数,所以接下来大家看第二种情况,14523623本来是不是应该在四五前面啊,但是他排到后面去了,乱序数据出现了。那所以现在的问题就又来了,按照之前我们那个规则啊,一这个数据来了之后,现在是一秒对吧?四来了之后这个是四秒,五来了之后是五秒,问题来了零到五秒窗口要不要关,按照我们之前的那个原则,是不是到这个场景下它就应该关掉啊。
07:14
零到五秒窗口是不是就应该关掉啊,那因为你时间已经进行到五了嘛,那如果说这个一定已已经把这个窗口关掉的话,大家想后面迟到数据,二跟三来了之后乱序数据啊,二跟三来了之后是不是就根本收不到窗口里面去了,直接就丢掉了,对不对。啊,所以大家会想到在这种场景下,呃,那我当前看到五秒的这个数据的时候,窗口该关吗?其实不应该关闭对吧,如果我想正确处理这个数据的话,那是不是就不应该关闭啊啊诶,那所以这里面就又有另外一个问题,就是说如果说这个窗口不关闭的话,我到底应该怎么来处理呢?
08:00
哎,有同学可能就想到那这个简单吗?对吧,我这我要处理这个后边来的这两条数据,二和三的这个乱序,呃乱序数据啊,这不就相当于我们之前说那个迟到数据吗?那比方说我就开一个窗口,然后后边呃再去比方说定义一个这个呃两秒的,呃,这个等待的这个延迟时间,对吧,然后我再等到他来了之后,我再更新一下这个结果不就完了吗?但是大家想啊,在实际的这个生产实际里边,我们当前面对的这个问题,其实应该是什么样子呢?我们这里面是把它当成秒了啊,但其实大家想这里面如果是时间戳的话。它的乱序其实应该是毫秒对不对,因为你想我们在实际生产环境里边数据因为这个分布式处理的这个乱序,它有可能达到秒级别嘛,说实话秒级别其实已经很大的一个一个乱序了,对吧,那就是如果说你网络比较差的话,那其实一般情况我们也就是几百毫秒,也一般达不到那个秒级别的延迟啊,那至于说已经这个数据进来之后,因为分布式处理导致的乱序,这个一般更达不到那个程度,一般都是毫秒级别或者几十毫秒级别。
09:13
那所以这里边就会有一个问题,大量的这个乱序数据,它可能集中在几十毫秒,几百毫秒范围内,然后呢,你这里边就相当于是那那家想我这里边如果要按照之前我们那个窗口处理迟到数据,那就那就是一个什么样子,我是不是到这儿的时候就直接先输出一个窗口近似的结果,后边我的那个迟到数据是大家还记得那个,呃,处理的规则是什么,是每来一个数据,是不是立刻更新一次结果啊。所以你会看到。在严格意义上啊,这个这个五秒的这个数据啊,来了之后,我马上输出了一个结果,然后后面在几十毫秒之内,然后大量的数据又来更新它对不对,每来一个就更新一次,每来一个就更新一次,大家觉得这个有必要吗?这个好像就就就非常的没必要对吧?就就觉得这个过程其实是已经有点呃太呃太太,这个就效率上就有点太低了啊,那大家想怎么样可以把这个更加简单的处理处理清楚呢?
10:19
其实大家想这就有点像我们这个,呃,这个坐班车去去这个定点发车一样,大家想一个窗口,这是不是就相当于比方说我们这个滚动窗口啊,呃,你像八点到9.1个窗口,这是不是就相当于呃,九点钟有一班车要要发对吧?然后我要坐这班车的人啊,八点到九点来的人都要上这班车,对吧?啊赶这班车,那大家可能会想到,假如说现在我的这种情况,好多要赶这班车的人,他就是在,就有可能要要迟到那么一会儿,对吧,就有可能是在九点到09:01,我们的出这个系统时间啊,我我现在说的这个时间是系统时间,就是在九点到09:01这个时间才要来,但是他本身要赶的是九点这班车。
11:07
那大家想他的事件时间是不是本来应该在八点到九点之间啊,啊对吧,所以他要赶这班车,但是呢,大量都在这个九点之后,那你说我是要到九点的时候,直接这个车就已经开走了,已经开起来了,然后让他来了之后再再追上我们来一个人我就开个门,上一个人来个门就开个门,有必要这样去做吗?这个这个没必要对吧,我们一般现实当中怎么做对是不是我我再多等你一分钟不就完了吗?对吧,我就直接把整个的发车时间朝后延迟一分钟,整体延后一分钟,这是不是就相当于大量的乱序数据在这个等待的过程当中就都到齐了。哎,所以大家就会想到我们这里边同样也可以这样去做啊,那这种做法其实是相当于就是在整个数据产生的这个时间戳基础上,给了一个滞后或者说延迟的时间,然后让我们啊这里面其实不是叫做延迟啊,这其实应该是说把当前的事件时间直接让它的进进展变慢了一点。
12:14
也就是说我给一个比方说给一个延迟三秒或者延迟两秒的时间,它相当于是把我们的视线时间呢,相当于把表给调慢了,对应我们那个赶车的场景,那就是我们全班同学啊,大家都要去这个比方说出去要做一个秋游,做一个春游啊,那大家想我们肯定是要坐同一班车出去的,比方说我们准时发车时间是九点钟,那这个时候我们可以怎么样呢?如果大部分同学都都可能啊,就是要要晚个一两分钟,那我现在有一种做法就是怎么样直接把司机师傅的表给他调慢两分钟。那大家想是不是最后我们的发车时间还是九点,只不过是已经调慢了之后的那个九点啊,哎,所以这就是我们在flink里边它处理这种啊,就是在可能几十毫秒之内啊,在大量的这个乱序数据,呃,我们的一种处理机制就是我直接把表调慢。
13:13
这种处理机制就叫做。Water mark,这就是所谓的水位线对吧?所以它的整体的原理其实就是说当一个时间戳,像五秒那个时间戳来了,他如果达到了窗口关闭的时间的话,我们并不是立刻就触发那个窗口的计算,然后就输出结果关关窗口,对吧?而是怎么样呢?而是稍微等一下,我们这里边所谓的等待,它并不是说像前面我们那个呃允许呃迟到数据的那个等待,对吧,它是直接把表调慢,意思就是说五秒钟的这个时间出来了之后呢,我认为现在时间没到五秒。比方说我认为时间只到三秒,只到两秒,那那大家想是不是零到五秒的窗口当然就不关啊,诶,那问题就来了,那我到底是什么时候才关这个五秒的窗口呢?
14:06
什么时候才关零到五秒这个窗口啊。按照我们这个调调慢表的这个规则。对,那大家想是不是我得继续等这个事件时间的推进啊,那大家想后面如果来乱序数据二和三来了之后,我现在这个时间能能往前走吗?走不了对吧?啊,这个肯定二和三你这个时间更更值钱嘛,啊,那所以五秒的数据来了,假如说我现在要延迟三秒啊啊,那我我是不是认为当前只进展到两秒啊,然后六秒的数据来了,因为我是统一波慢了三秒嘛,那是不是六秒来了之后,我现在可以认为时间进行到三秒了。那所以就是假如你有三秒钟要关的窗口,我现在可以关了。那所以大家就想到了,后边我这个零到五秒窗口应该什么时候关。是不是应该是对七跟八八来了之后,是不是就代表当前的这个,呃,时间进展到五秒了,这个时候才是前面零到五秒的窗口,该关就关闭了。
15:09
啊,所以对于这个walmark而言,它其实是一个用来衡量事件时间进展的机制,也就是他取代了我们之前说的那个事件时间的时间戳,对吧,变成了我们当前事件时间的那个表,它的时间到底是多少,是我们调慢了之后的那个表,所以它可以设置一个延迟触发,对吧,可以把这个表稍微调慢一点,所以它一般应用在什么场景下呢?就是用来处理乱序事件啊,那所以一般我们正确要处理它的话,要用这个watermark再结合window来做一个实件。这是什么意思呢?大家就会想到这个walmark,它是不是主要处理的是短时间内大量的那个迟到的乱序的数据啊,所以它其实大家想它的这个延迟时间是不是相当于我们整体就延迟了。
16:02
啊,所以一般他会设一个相对来讲比较小的统一的这样一个延迟时间,然后大家就会想到,假如说我设了这个几百毫秒对吧,或者设了这个一两秒的这样的一个,呃,Automark的一个延迟表调慢了,那假如说还有些数据没到呢。对吧,我设了这个500毫秒的一个water rock延迟,还有数据没到,那怎么办呢。那对,这个时候我是不是可以用window的那个API了,把它允许处理十道数据,比方说我再等一分钟,哎,这就对比我们的那个坐车的例子的话,那就相当于大部分的同学可能都是在要赶九点的班车,都是在九点到09:01这个时间内来,所以我就直接把表调慢一分钟,对吧,大部分同学就都上来了,但是有个别同学呢,哎,可能就是要要在09:10才来。那这个情况下那怎么办?那我就就是相当于我这个就不要直接停在这儿等你了,那我这个车就相当于先往前开,但是呢,慢慢悠悠开,大家想这个既然是开车,是不是相当于对应窗口那边就要输出一个结果啊,对吧,先输出一个结果,但是接下来我后面还可以更新,因为我是不是我这我这个窗口是不是就没关啊,对吧,所以我这个车还是慢慢悠悠开,车门也没关,接下来你如果赶得及的话,你接下来的十分钟之内,只要你来了,你打个车对吧,或者说这个呃,打个摩的什么的啊,各种穿街走巷,然后追上,那接下来你还可以上车,我还可以再聚合一次,输出一个新的结果,这就是我们这个窗口允许处理十分钟的数据,那假如说还有漏网之鱼呢,还有一些同学就更更久对吧,十分钟还没到,那怎么办?那不好意思,我不等了,车门关上,直接上高速跑了,那接下来是不是,哎,那如果说我们正确想处理数据,我们要大家一个班同学全要出去秋游。
17:55
啊,那是不是一个都不能少啊,那那没关系,你再等下一班车吧,对吧,我们先去了,然后你等下一班车之后,你再做一个批处理,再聚合在一起,对吧,大家在一起去玩,所以大家看这就是我们说的特殊出流嘛,对吧,窗口的特殊出流,所以在处理这个乱序数据的时候,Flink可以说是有三重保证,首先water mark就可以整体上把那个短时间内啊,几百毫秒之内的那些乱序数据全部直接hold住。
18:27
然后呢,如果他hold不住的那些数据呢,我们还可以对到点的时候,他是先输出了一个近似正确的结果,那我们后面还可以allow lateness,等待一段时间来一个数据就更新一次窗口结果,对吧?那等到这个等待的时间也到了之后,窗口关了,车已经发了,对吧?那那怎么办呢?Set out put late data测殊处理,这是我们兜底的方法,至少保证数据不丢对吧?哎,所以大家看,这就是这个处理乱序数据啊,在弗林里边一套机制。把我们之前那个拉姆达架构两套系统保证的东西全部搞定了啊,这就是watermark的一个特点啊呃,那么这里面有一个概念,就是说它其实watermark是用来表示时间戳小于watermark的数据都到齐了对吧?那所以它其实表示的就是如果我们能正确处理的话,那就是说我设置这个water mark延迟三秒钟,那你看是不是就相当于五这个数据来了之后,当前的water mark是二,是不是表示二之前的数都到齐了,二和三是不是还可以来啊啊对吧?哎,所以那那后面二和三来了之后,我就还可以继续处理对吧?六来了之后,现在watermark到三,这表示三之前的数都到齐了,对吧?啊,所以接下来就是三以前的啊,一和二不会再来了,那它后面345可能还还可以来啊,所以它是这样的一个概念,那这里边其实就是watermark呢,是让我们自己程序里边可以去。
19:58
平衡延迟和结果的正确性,这个怎么来理解呢?
20:04
这其实就是说大家想,如果说我想让这个程序延迟更低一点,更快一点,但你的watermark是不是就设小一点啊,对吧,你就不用不用那个等更多的乱区数据嘛,但是大家想那结果是不是就有可能不正确啊,那你如果想要结果非常正确,那我是不是可以把这个watermark设大呀,你甚至都可以把automark设一分钟,大家想你就相当于是什么,我把那个之前我们说的那个allow late的那个功能直接就就涵盖了,对吧?而且它在这一分钟之内,注意啊,它是不会直接输出结果的,是不是一定要因为你把表都直接播慢了嘛,是一定要等到这一分钟都都已经过了之后才会输出结果对吧?啊,那大家自然就会想到我们实际应用的过程当中,这个应该怎么设呢?是不是不能太大也不能太小啊,啊对吧,所以这里边就是一个权衡了,你如果设的太大,结果是对了,但是延迟太高了,你如果设的太小的话,诶,是不是快是快了,但是结果很不正确啊,所以这里边其实就是要有一个权衡的过程,这就是关于water mark的概念和原理。
我来说两句