00:00
大家给大家要讲的是另外一个弗link当中非常有特色的内容,那就是时间和窗口啊,因为在流处理里边,大家知道我们是按照这个事件发生的顺序啊,一个一个来做处理的,一个非常重要的也非常常见的操作,那就是。我要收集一段时间内的数据,然后统计出一个结果,做出一个分析,比方说我们说的这个日活,比方说你像这个PVUV啊,往往都是基于一段时间啊,啊一天一周,然后去去算这样的一些对应的统计指标的,所以时间呃,就是所谓的这个窗口,那又是基于什么呢?那都是基于时间嘛,啊所以在flink里边。特别是就是所谓的流处理里边啊,弗Li克也不例外,就是时间和窗口都是非常重要的概念啊,我们需要基于时间去开启窗口,收集数据,然后去做统计和计算,接下来我们就深入的去了解一下。Link里边的时间和窗口。
01:02
提到时间,大家可能觉得这有什么好讲的呢?时间不就是不停流逝的这样一个表明我们这个世界运转的一个机制吧?呃,那对于这个计算机系统而言,这不就是系统时间吗?你只要把那个系统时间配好了之后不就完事了吗?诶,但是仔细想的话,还没这么简单。一般情况而言,对于一台机器,我们获取当前时间,当然拿到的就是系统时间,但我们现在只有一台机器吗?不是的。我们现在是一个分布式的系统,而且要处理的数据是源源不断来的,所以数据也不是同时产生,也不是同时进入我们的flink系统,而且也不是同时处理的,那这个时候就会有一个差别,就是。数据产生的时间和进入flink的时间,以及某一个运算来处理这条数据的时间,他们是完全不一样的,所以大家可以看一下这张图。
02:00
首先。事件会发生,事件发生的时候,我们应该能够有条件记录一下当时它发生的这个时间啊,大家知道收集数据吗?比方说前面我们这个用户的访问,呃,页面啊,点击的那个事件,我们收集日志的话,肯定就会有一个time stamp把这个会写到这个日志文件里边去,所以事件发生的时候会有一个事件,事件,我们把它叫做事件事件。这是一个时间,然后。我们会把所有事件发生的那个日志收集起来,比如说写入到消息队列里面,卡夫卡就来了,对吧?啊,然后接下来呢,弗link我们可以呃,设置一个这个原算子去读取卡夫卡里边的数据啊,这flink卡夫卡consumer,然后把它读进来,这里又有一个进入弗link系统的时间,当然这里边没有展示出来啊,大家知道这个时间比事件时间的话就会有所延迟。而且大家知道,如果像卡夫卡这种分布式的消息队列的话,在分布式传输的过程当中有可能会出现什么呢?会出现乱序。
03:07
就是我这边事件发生的。时候啊,诶。边有可能先发生了一个事件圆圈,又发生了一个事件三角,那么经过这个消息队列传递的时候呢?哎,那有可能它这个分区传递了,有可能圆圈在这边,三角在这边。那就看到是不是就有可能会出现三角先进到弗林系统里边来啊,诶,所以这个时间就不光是比之前有所滞后,而且顺序都有可能发生打乱。然后接下来呢,在flink里边,它又是一个分布式的结构,而且是一个data flow流式的处理方式,所有的先后发生的任务是分别计算的,那么数据通过数据原算子读进来之后,这个算子任务读进来之后,接下来会朝下游的转换算子去传递。
04:00
比方说下游我们就直接开窗去做计算了,那就会有一个窗口算子,这个窗口算子接收到数据进行处理的时候,跟之前又有一个延迟,而且又有可能要去打乱,因为我不知道到底是并行的哪个任务去执行这条数据嘛,啊有可能这个三角这条数据又到了上边,圆这条数据又到了下边来了。当前的这个顺序呢,那跟之前就又乱了对吧,啊就就又不知道变成什么样子了,所以大家会发现这就涉及到了三个事件,一个是事件发生的真正发生的那个时间。我们把它叫做even type事件时间,另外一个是进入link系统的时间啊,有些地方我们会把这个叫做摄入时间interesting time啊,或者叫这个进入时间,到达时间啊,那这个东西可能不是特别重要,我们更加关心的是具体的任务,在处理这条数据的时候,这又有一个时间,这个叫做处理时间processing time。
05:00
他们本身这几个时间彼此之间是不一样的,是有延迟的,而且在处理数据的时候是会发生乱序的情况啊,那那这就是关于flink里边不同的时间语义的一个定义,我们首先要建立这样的一个概念。现在就有一个一个问题啊,既然有不同的时间语义,比较重要的就是一个是事件时间even type,另外一个是处理时间processing type,那我们实际使用的时候到底用哪种?时间语义呢,诶这两种时间语义是有不同含义的啊,呃,因为大家知道,呃,这个对于我们这个窗口而言非常重要,就是什么呢?比方说我开启一个今天早上八点到九点的窗口。我要统计,也就是说要统计八点,八点到九点的数据,对吧?哎,那现在时间语义就很重要了,就是说你到底这个八点到九点是事件发生的时间还是处理的时间呢。
06:02
诶,我们自然想到了,如果说你只按当前的系统时间,机器时间来算的话,那肯定这就是处理时间了,就是我只看八点到九点。当前的这个任务啊,所在的这个机器,它上面的时间是八点到九点,接收到的所有数据,我就把它收集起来去做一个统计计算,哎,这就是使用了处理时间,而另外一种方式呢。我是按照事件,事件也就是说当前这个机器到底是几点没关系,我是要看你的事件是八点到九点发生的,我就把它收集起来做一个统计计算啊,所以这两种方式是完全不同的。那我们就涉及到一个。考量啊,具体考虑的时候,在执行任务的时候,我们到底应该用哪种时间。哎,这里边我们就要讨论一下这个话题啊,就是哪种时间语义更重要。这里有一个非常经典的案例,我这里又给大家画出来了啊,这就是一个电影的啊,非常有名的经典电影啊,星球大战,星球大战这个有些同学可能看过啊,有些同学可能即使没看过应该也听说过,因为这是一个要说早的话是一个很老的电影了啊,呃,就是。
07:18
最早的一部是1977年就已经拍了啊,大家知道这个经典电影往往都有这样的一个一个一个问题啊,就是一部电影如果它又叫好又叫座啊,特别经典,那么后续往往就会拍续集啊,所以大家看七七年拍了第一部之后,80年83年分别就拍了他的两部续集。然后呢,呃,因为大家会发现这个形成系列电影之后,可能就形成了一个一个叙事的世界观啊,那他就不光这是一个著名的IP了嘛,那就不光基于他要拍续集,还有可能要拍前传啊,所以你看这个过了十几年之后啊,又翻回头来。拍了他的几部前传。三部前传。
08:01
啊,然后呢,又过了这个十年左右,到一几年的时候,2015年又开始拍后面的续集,如果你要是完全没有看过这个星球大战的人,你如果要是现在想去看这个电影的话,到底应该从哪部电影看起呢?哎,所以这里边就涉及到两种的观影顺序,我们可以给他做一个排序,一种非常简单,那就是按照它上映的时间,诶哪一步先让印,我就先看哪一步,这就有点像采用了什么呢?采用了处理时间啊,就是你什么时候上的,就是我我什么时候接收到,先接收到这个这个数据,我就先去处理它,对吧,这就是按处理时间来来观影,那如果说我是想充分了解这个故事的话。那是不是要按照这个故事发生的时间呀,哎,所以我是应该先看前传,先看这个123,然后再翻回头来头来看这个经典的三部曲,经典三部曲其实是456对吧?啊,那那所以是这样的一个观影顺序,然后再看后边一几年拍的这些啊,后面这个789,所以这就看你到底是什么类型的影迷了啊,那有同学可能说我我是这个。
09:11
就是特别特别喜欢这个看剧情啊,我喜欢看这个故事,那最好的观影顺序就应该是按照这个编号顺序,按照故事发生的时间。所以我们采用的就是事件事件,那如果说呃,你你比较感兴趣的,比方说你想看的是这个特效啊,你你对这个电影的发展,电影这个技术的进步特别感兴趣啊,那这样的话,最好的顺序那就按这个拍摄时间来看就可以了,对吧?啊,那理论上来讲,一几年拍的东西比七几年的东西,肯定它的那个效果啊,特效什么的是要好很多的,那你如果只看特效的话,看了后面的肯定你就不想看前面的了啊,所以大家看到两种不同的时间语义啊,各有各的用途,它们分别有不同的适用场景。那在计算机系统里边,到底什么样的语义更加重要呢?啊,那我们就想到了,你计算机系统里边,你你要考虑它特效吗?你要考虑这个数据,它这个不同时代的这个演变吗?啊,这这个并不关心对吧,所以我们往往更关心的是什么呢?就是数据到底什么时候产生的。
10:19
比方说像前面我们说的八点到九点钟的窗口,这个大家可能还还看的不是很明显啊,那比方说我们说日活。诶,你说你要统计昨天一天的日活,你难道要看的是接收到数据的时间吗?哎,如果这中间这个,呃,就是这个延迟,我们说这个从从前面到后面这个是有时间延迟的嘛,统计日活的话,那假如某一条数据是昨天晚上11点23:59:59发生的。但是经过网络传输啊,消息队列读进这个flink,然后到达我们这个窗口算子的时候,已经到了第二天的。
11:00
0.01秒。那大家会想到当前这个数据我应该算昨天的日活吗?当然应该算,因为你算日活是看昨天时间范围内用户的点击,用户的这个活跃的程度,用户的这个数据,你并不是看我当前数据的处理的时间呀,那特别是数据量特别大的时候,你有可能这个时间呃,这个延延迟很高,那这种情况你就会出现错误啊,统计就会出现出现问题啊,那如果要是对这个呃时效性要求更高的那些,比方说你要实时检测,然后报警,对吧,做这种做做这种风险控制的话,那这个更更是你必须要按照这个事件发生的时间才是有道理的。啊,那所以在实际应用的时候,往往我们使用的是事件时间,那使用事件时间接下来我们应该怎么样去在代码当中去处理它呢?那一般情况就是数据产生的时候,这个时间就确定了,一般我们会把它写在日志里边,以时间戳的形式,所以大家可以看到我们前面那个event里边也有一个time stamp这样一个属性,我们就需要做的就是从原始的日志数据里边把这个时间戳提取出来,作为当前事件发生的时间,然后按照这个时间把它分配到对应的窗口里面去。
12:20
诶,那这里面大家就会发现了,你现在是光有了对应的这个时间,每每一个数据的时间戳,只知道了这个数据应该分到哪个窗口。但是这里还有一个另外一个问题,就是说我当前这个窗口到底应该去怎么关呢?那就是前面我们说的,比方说八点到九点的一个窗口,那大家自然想到,如果是处理时间与意义的话,这个很简单啊,我我就是看当前这个系统时间嘛,到九点诶这个窗口直接关了对吧,然后直接做计算输出结果完事。但如果是事件时间呢?事件时间,那我是不是就得看当前这个数据里边带的时间,戳到对应的那个时间才能够关闭这个窗口啊,啊这种情况下,其实我们是在这个系统里边要有另外的一个时钟去表达当前时间的进展的。
13:12
这在flink里边呢,它是单独的提出了另外一套体系,衡量事件时间进展的这个时钟,这个机制就叫做事件时间的水位线watermark啊,这个我们先提一句,后边再给大家详细的讲解这个概念。
我来说两句