00:00
我们现在已经了解了在flink当中怎么样去生成水位线啊,我们知道可以直接调用系统内置的水位线生成器,也可以自定义水位线的生成策略。另外呢,我们还可以在。自定义的数据源当中去发送水位线,有了这些知识之后,接下来我们再来介绍一下水位线的传递规则,哎,这是考虑一个什么问题呢?主要就是说在之前我们介绍水位线的传递原理啊,生成策略的时候呢,我们考虑的场景其实就是这样的,所有数据排成一列,然后依次传递的这个过程。那作为一个特殊的数据,我们把水位线看成插入到数据流里面的特殊数据,它就可以随着正常的数据一起向前流动,那假如说啊,我们知道flink的处理就像一个流水线一样嘛,一个一个的工位,这就是一个一个的算子任务。那数据不停的在它们中间流动,水位线跟在后边的话,诶,那当然了,也可以继续流动,按照顺序继续流动,这是完全没有问题的。
01:08
但是这种方式太简单了,我们知道flink本身是一个分布式的处理系统,所以呢,上下游任务它可能都有很多个并行子任务。这里就涉及到一个问题啊,就是我们当前假如出现了一个算子任务,它的并行子任务上处理完的数据想要发送到多个下游的并行子任务。接下来又应该怎么发呢?诶,这个其实比较简单,之前我们说既然它是表示时间嘛,数据的话啊,是按照我们之前所说的这个重分区策略,那就是啊,要不就是正常情况下默认re balance啊,那我们就是依次发牌啊,那或者呢,我们也可以洗牌杀Le,另外我们也可以按照分组来进行发牌,各种各样的传递都是可以的,那如果说当前是一个水位线的话,那怎么办呢?
02:03
它是一个时间的标志,所以我们应该直接广播出去。广播到下游的所有并行子任务就可以了,这种方式比较简单。那另外我们考虑到。对于下游任务来讲,它的上游给他发送数据和水位线的,也可能有多个并行的子任务啊。那这个时候他又应该怎么办呢?那我们会发现在这种场景下,就是有可能出现什么情况,上游的并行子任务它是各自为政的嘛,每个并行子任务的时钟有可能不一样,它的水位线进展不一样,那就有可能,哎,我第一个分区给传递过来的水位线,哎,进展到了十秒。但是呢,后边第二个分区来的水位线只进展到了八秒,第三个分区只进展到了六秒。那这个时候,当前的下游任务到底按哪个时间作为自己的事件时钟呢?
03:00
这就是我们当前要考虑的水位线传递规则的问题啊,我们可以在这里看一个具体的例子啊,我们看到当前有一个任务在这里呢,我们只考虑某一个算子,然后我们考虑它的一个并行子任务啊,因为我们知道啊,当前任务如果有很多个的话,比方说这里有一步map操作,有很多个并行子任务的话,每一个并行子任务之间他们的。事件时间可以完全不同,他们的水位线彼此互不影响,那谁会影响到当前这个任务分区,它的时间进展呢?其实是它的上游任务诶,所以我们这里关键要考虑它的上游有多少个并行子任务,另外呢,它本身它的时间进展又会影响到他所有的下游并行子任务。所以其实我们就是针对当前任务扩展,考虑它的所有上游并行子任务和下游并行子任务就可以了。
04:00
那当前这个例子呢,我们就可以看到这一个分区子任务,它上游有四个并行子任务,四条线都在传递数据和水位线,下游呢有三个分区,三个并行子任务啊,那我们就朝三个分区去发送就可以,那其实朝下游发送这个我们知道比较简单啊,直接广播就可以,那上游啊数据我们就不管了啊,数据的传递策略我们都已经考虑过了,这个时候我们只考虑水位线。不同的分区传来了不同的水位线,这个时候以谁为准呢?诶,这个时候我们就要回归到水位线的本质来进行考虑,水位线表示的是当前的时间已经进展到了这个时间点,那么就是小于等于当前时刻的所有数据都到齐了,所有事件都发生了啊,那比方说我们上游某一个分区传过来一个水位线是四啊,我们把这个就看成是秒数吧,那就是小于等于四秒,也就是说四秒之前的数据都到齐了。
05:03
第二个分区传来的是七,那就表示这个分区七秒之前的数据都到齐,都处理完了,那下一个分区是六,那就是六秒之前的数据都到齐了,都已经处理完了,那所以我们说当前的这个task它应该以谁为准呢?哎,那我们想当然是应该以时间最小的那个为准,好,因为对于后边啊,时间已经进展到七的这一个分区而言,那当然四之前所有的数据都已经处理完了嘛,但是对于时间进展比较慢的这一个分区而言,那七之前的数据有可能还没到,如果我们task直接把自己的时钟定义成七的话。那就有可能丢掉第一个分区,接下来传来的数据啊,就是它就不再处理了嘛,就变成迟到数据了,所以我们当前应该以所有分区发来的水位线里边最小的那个为准,这就是木桶原理嘛,短板决定了我们当前时间的进展。
06:04
啊,所以在具体实践上我们看到啊,当前的这个任务,他会给自己的每一个给他发送数据的上游并行分区,设置一个分区的水位线。也就是说我们会把上游每一个分区的水位线都单独的做一个保存,那保存下来之后呢,比方说现在啊,有四个上游并行子任务,那有四个分区水位线当前是2436,这是接收到的,那么现在当前任务的事件时间进展到了什么时候呢?就进展到了二。以最小的这个为准,代表我们当前所有二之前的,也就是两秒之前的所有数据都已经到齐,并且都已经处理完毕了。因为我们上游的所有分区啊,都能保证这一点,所以当然我当前的这个任务也可以保证这一点。所以接下来他会把这个两秒钟的水位线广播到自己的下游任务。
07:03
那接下来呢,我们看到呃,前面的这个数据是不停的传输的嘛,水位线也会不停的更新,上游任务又来了一个水位线,第一个分区传递来了一个四,那这个时候我们就把它的分区水位线做一个更新,变成了四。这个时候呢,再做一次判断,判断当前所有分区水位线最小值是否八发生了变化,我们看到现在变成了三,那么就把它的事件时钟。推进到三,表示三之前的所有事件,三秒之前的所有数据都已经到期处理完毕了,那么接下来他就可以通知自己的下游广播三秒这个水平线,告诉所有的下游并行子任务,我的时间已经进展到了三秒,三秒之前的数据我再也不会发送给你们了,哎,这就相当于时间就整体往前推进了。然后接下来呢,第二个分区又来了一个七,同样需要去更新它的分区水位线,这个时候呢,我们一判断,诶,最小值还是三,那这个时候就不更新时钟,当然了,我们说如果他不更新时钟的话,其实就没有必要再去广播通知下游嘛,之前我们已经通知了,时间进展到三了,时钟没变,哎,那我们就可以节省资源,不再发送,那如果接下来又来了一个六,同样这里我们要更新对应的分区水位线,再做一次判断,发现最小的水位线已经变成了四,那同样就要更新当前自己这个任务的时钟,我已经进展到了四,然后呢,把四水位线广播到下游的并行子任务。
08:39
这就是我们所说的啊,在不同的并行子任务之间,前后发生的上下游任务之间有多个分区的时候,水位线它的传递规则啊,所以我们看到啊,利用这种方式其实就非常巧妙的避免了分布式系统当中我们没有统一的时钟啊,那大家各自为证怎么办呢?没关系,我就接收上游不同分区发来的水位线,然后呢,以他们最小的那个为准来控制我自己的时间就可以了啊,当然我们会发现啊,那相对来讲,因为这里是木桶原理,以短板为准嘛,那如果要是发送数据快的,处理数据快的那一个分区,它的时间进展快,那相当于到这里就会再多等待一会儿啊,那所以这里边就对应的有个一个延迟等待的过程。
09:27
通过这样的方式保证了我们最后结果处理的正确性,那另外呢,呃,对于如果有多条流,哎,我们说读进了两条流。所有的数据它的时间可能是不一样的呀,事件时间不同诶,那么接下来如果两条流又汇合在一起,做了一个合并。接下来河流之后的时间又是怎么样的呢?哎,这个传递规则跟我们这里讲到的上下游之间的并行传递是一样的,所以关于多流转换这一部分,我们会放在后边的章节进行进一步的讲解,这就是关于水位线的传递。
我来说两句