00:00
好,接下来呢,我们准备要给大家讲一讲检查点的具体实现算法,那涉及到这个算法,那我们就首先来思考,前面我们讲了当前保存checkpoint保存所有任务状态,它是要求是所有任务都处理完同一个数据之后的状态,哎,那大家就想一下,如果让你设计这个系统啊,你用一个什么样的思路来做这样的一个保存呢?其实checkpoint的这个概念大家也不陌生,Spark里边也有,那Spark里边的checkpoint应该怎么做呢?哎,大家想其实这s Spark里边没有那么呃,那么复杂的东西啊,我们是不是就相当于因为它有stage嘛,呃,所以按照这个stage划分,大家想它本来就是有一个阶段性的一个一个成果的保存,对不对,我就直接把这一阶段啊,最后的那个所有数据是不是直接保存一下,这就是一个checkpoint呀,诶所以这个过程其实非常简单,并没有涉及到什么算法之类的问题,但是现在流数据处理的过程当中就涉及到了这个问题,因为首先我这里边拿不到所有的数据,对吧,我的数据是源源不断来的,这是前提,你不能直接把所有数据保存,这个是不现实的。另外啊,大家会想到就是当前我能划分这个stage,等到所有数据我想要的数据都到齐了之后,然后我去做一个保存吗。
01:22
好像也不行对吧,因为你像我们之前那个stage的话,就相当于是所有的任务我都得等当前的这个任务stage做完了之后,我才进行下一个阶段,所以那自然在这个两个stage之间我就可以做一个保存了,那像现在我们这个flink里面是不是所有任务都是连续不断在做的呀,没有中间要停的这个stage这个阶段,那你到底是在什么时候才能说明我当前这个数据是所有任务都处理完了呢?有一个简单的想法,大家可能会想到,那你这个就是你喊一个,比方说我在一个这个数据后边啊,就是跟跟上跟上一个标记对吧,就是所有任务遇到这个这个数据后面这个标记的时候,我直接喊停,直接咔对吧。
02:11
他就直接在那等着,然后就等我们其他的任务处理这个数据,他们都处理完成之后,然后接下来我们开始统一把现在的状态做一个保存啊,然后接下来是不是,呃,就是全部保存完成之后,我再开始重新开始启动,重新读数据,重新处理啊,这是一个简单的想法,对吧?但大家想这个有没有什么问题?这个问题就是非常简单粗暴,停止一切对吧?所有的任务是不是全停下了?就等着大家先把手头活都做完,然后再合起来一起拍张快照,然后接下来再重新开始干其他的活啊。啊,如果要跟我们平常的这个拍照片类比的话,大家可以联想一下啊,如果我们我们班同学大家要毕业了,一起要拍一张集体照,那那有些同学可能就会,呃,有这样的一个体会啊,像我的话就是非常也不能说讨厌,因为本身拍照是对大家来讲比较有意义的一件事啊,但是拍照的过程很麻烦。
03:11
因为我们拍集体道的时候,是不是每个人现在的状态不一样,对吧?哎,大家有可能在干不同的事儿,要拍照的时候,必须要让大家先把手头的事儿全停下,然后是不是下去要排队啊,哎,那有可能有的同学下去快,有些同学同学下去慢,那这个过程就要等半天,其他先下去的同学都在那儿等着,然后等大家都站齐了,然后我们说123茄子拍张照片,快照生成了,然后大家再回回过,回过头来该干什么,继续干之前的事儿,这就是大家熟悉的拍快照的功这这种方式,对吧?那么在这个,呃,Spark,我们划分stage去拍快照的时候,大家看也是类似于这样的一个思路。那flink里边我们要快要本来我们就要它这个低延迟,对吧,本来系统处理设计的时候,我们任何一个地方都是希望做到这个低延迟这个特性,而你这里边呢,为了保证容错,中间就直接把所有任务都停掉,让大家先去排队去拍照,这个代价太大了,对吧。
04:11
那大家想一想,我可以用一个什么样的方式来做这件事呢?啊,有有同学说这个这就相当于我们可以做一个异步的这样的一个拍照快照,对吧?哎,那这里边类似于这样的一个思想啊,我们这里面其实做的操作就是每个人单独去做快照。大家想到有这种实现的方式吗?其实可以的,你像我们最后如果要想生成一张快照的话,我们只要判断当前就是啊,就是大家这个这个时间段对吧,学习完成之后的这个这个状态,那其实只要是你这个人现在这个时间点不就可以了吗?那我就只要把你这个人抓到,比方说我们要拍的都是学习完flink之后你的这个状态,我们形成一张快照,那是不是就是大家的进度不一样,有同学可能提前都已经学完了啊,那是你学完之后,那就直接啊,就是找到班主任老师直接给你单独拍一张照片,好没问题了,你接下来你继续呃,学后面的东西吧,或者做其他事情吧,那另外的一位同学有可能是隔两天之后才学完,对吧?啊,代码敲的比较慢,诶那就没关系啊,你前面该做什么继续做啊,等到你两天之后做完这个flink了,呃,那么同样找到班主任老师拍一张照片,那最后怎么样才是一张合照呢?
05:29
对,最后是不是P在一起就可以了呀,所有的每个人的这个头像P在一起,这不就是我们当前所有人都学习完flink之后啊,当前这个时间点状态,大家放在一起的一张合照吗?啊,当然在现实当中我们一般不会这么去干啊,啊那大家知道现实当中主要是P图这个这个工作太费劲了,对吧?啊,这还不如让大家下去排个队呢啊,而且就是说这个可能班主任老师要花费大量的时间,但是大家想一下,如果在这个我们当前的计算机系统里边啊,分布知识系统里边拼图这个工作费劲吗?
06:08
不费劲儿对吧,我们不需要用哈,呃,这里面你如果要是把不同的这个快照拼在一起的话,大家想之前我们做这个拆point的时候,这是不是就直接把它放在一起,然后有一个这个拓扑结构,指指明是是什么就可以了,那你说我这里面P图的时候是也是这样的方式对不对?你单个发给我,然后我知道,只要知道是哪个任务的快照不就完了吗?所以这个完全就没有,呃,没有,可以说是没有任何附加的这个工作量,而且这个工作量应该是由谁来做啊,即使是有的话,这个工作量是由那对由job manager由他来P图来来做这个,呃,拼接对吧,那我们task manager是不是该干什么继续干啊对吧?那甚至前面大家还看到了,我们在这个checkpoint配置里边是可以去设一个异步进行checkpoint操作,那就是相当于我这儿的这个状态,是不是我先单独的存,就是存一个副本存出来,然后接下来我该做什么操作继续做。
07:11
那后续是不是我就直接把那个副本慢慢的存到那个远程的存储系统上就可以了。诶,有同学可能说为什么非要把这个单独存一个副本才能去做这个异步呢。那是因为后边你如果再处理数据的话,是不是会改这个状态啊,你一边往后存,一边这个状态还在改,那是不是肯定有问题啊,哎,所以最好的状态,最好的保证这个正确性的话,应该是同步,就是说我等这个状态全存完了之后,然后再去处理下一个数据,对吧?如果你觉得连这个都不能等的话,那我就先把它复制一个副本,大家知道知这个副本是不是只在内存里边复制一份就可以了,这个速度比较快,你往外部那个落盘写的时候速度比较慢,对吧?这个涉及到这个IO啊,所以这就是我们对于这一个拆po做保存的时候啊,从时效性上,从从这个呃,系统的性能上做优化的一些考量,一些设计,所以弗link底层也确实就是用到了这样的一个思路,它具体的实现呢,呃,就是他没有把所有的这个任务都都停掉,去做快照保存,它真的是就是像我们前面说的那样,挨个自己分别去保存自己的状态,最后再拼在一起就可以了。所以。
08:25
这个是有一个说法的,这种算法叫做基于超级兰波特算法的一个分布式快照算法啊,这种算法叫分布式快照,对吧,就分别去做,最后再拼起来。呃,那么它的主体想法,主体思路就是把检查点的保存和数据处理直接都分离开,你自己就保存自己的,那大家想前面我们讲到每一个同学下去单独做快照的时候,别人下去做快照的时候,诶,你自己这个有影响吗?你该干什么还干什么,对吧?你如果手头这个福林课没做完的话,你继续往后看啊,等到你做完之后,你再下去自己拍就完事了,对吧?或者说像前面已经学的比较快的同学,他已经拍完照片了,其他同学拍的时候,他要在那儿看着,在那儿等了。
09:11
也不用对吧,那后面继续我已经拍完了嘛,接下来这个都是班主任老师的事儿了,所以他就继续该处理后面的数据,处理后面数据就完了,所以整个的过程不会暂停,甚至每一个任务都是流失处理,都是就完全不不等对吧?呃,跟周围的那个任务它也不关心,只关注保存自己的状态就可以了。这就是整体的一个实现思路。那具体来讲的话,大家可能会想在这个具体的这个底层啊,数据结构里边,到底是怎么样去判断当前我应该做这个快照了呢。我们现在不是有前前后后有有很多个这个任务吗?大家想我怎么样能判断当前这个任务就该做这个快照保存了,完成完一个数据了。
10:01
我们当时说的是这个数据来了之后,处理完某一个数据之后,我要做一个快照保存,对吧?哎,那有同学是不是就想到我是不是相当于可以再多一个标记啊。就在当前这个数据后边再追加一个标记,那是不是就可以接下来,但大家想这个标记,这是不是就代表我数据已经处理完了,接下来要去做状态保存存盘的这个事情了。哎,所以大家看啊,在这个flink底层,它的实现是用到了一个叫做所谓检查点分界线这样的一个一个东西,一个概念,这个英文源码里面的名称叫做checkpoint barrier barrier的话大家知道它翻译过来其实有这个。有屏障对吧,离板,然后这个呃,分界线啊,类似于这样的一些概念啊,所以有些地方可能会把它叫做检查点屏障啊,或者说这里边叫检查点分隔符啊,呃,叫什么都可以,我这里边翻译叫检查点分界线,它的含义是什么呢?就是我们在数据流里边插入一个叫做barrier的特殊的数据。
11:15
这就有点像我们那个watermark一样,Watermark我们之前就是说它可以理解成一个特殊的数据,数据类型,对吧,插入的一个特殊的数据,那我们现在呢,也是在流里边插入一个特殊的数据,这个叫做barrier。那大家就看到了,这个barrier代代表的含义,它是什么呢?就是把我们一条流上的数据按照不同的检查点分隔开,所以它叫做分界线,对吧?诶,那那具体来讲,我们每一个任务啊,既然说它是一个特殊的数据嘛,那之前我们说过正常数据这个任务来了之后,那是做这个任务的处理,对吧?如果是map方式的话,我就调那个map方法,如果是process,呃,那个底层API的话,我就调那个process element嘛,来一个处理一个后,后面如果遇到的是watermark的话,大家还记得我要做的是不是就是判断那个当前时间的那些操作啊,对吧?有可能是要关关这个窗口啊,推进当前的实践时钟,然后去做对应的一些操作,那假如说我现在来了一个barrier,现在要干什么呢?
12:21
哎,他做的操作是不是就是直接把当前的状态做一个保存啊,哎,我当前可能自己这里边有一个自己的状态,那大家看是不是现在的过程就是第一个数据来了之后,假如说我是增量聚合的啊,那是不是要更改一下这里的状态啊,那比方说这里count的数量加一对吧,然后输出结果,然后第二个数据来了之后,抗的数量再加一变成二输出结果对吧,然后第三个。Count状态变三,然后输出结果,然后接下来大家注意这里边遇到barrier了怎么办?是不是状态三直接保存到状态后端stay back end上面去啊,啊,但是这个缩写有点奇怪啊,大家知道是stay back end就可以了,是吧?好啊,那所以接下来大家就会发现它其实是不是之前所有的数据带来的那个状态改变都在当前的这个对应的这个checkpoint里边啊,所以大家看这个一个barrier是不是就代表了一个checkpoint的保存的那个时间节点。
13:25
呃,然后之后的数据呢,之后的数据它的那个状态会会保存在这里边吗。它就不会保存在里边,对吧,那它属于属于在哪里呢?对大家想是不是下面如果又来了一个barrier的话,它的那个状态应该保存在这个barrier对应的那一次拆框的保存里边啊哦,所以大家会想到,假如说我如果在这个barri之后啊,处理完这个,比方说这个count变四,后面count变五,假如说在这挂了。那接下来会怎么样呢?接下来是不是后边的这个这个检查点还没做完保存啊,对吧,这个还还没做呢啊,刚处理了两个数据还没来,遇到后面的这个barrier呢,没保存,那是不是这两个处理的数据这个状态应该要丢掉啊。
14:10
后面我们是不是要重放数据,所以大家看是不是我就基于之前的这个barrier对应的那个checkpoint的状态恢复出来,恢复出来的状态是不是就是只处理完前面的所有数据的状态啊,那所以大家看接下来是不是那个SS任务是不是也刚好就是处理完这个的状态,那是不是接下来重放这两个数据就可以了啊?所以大家看这就是bar的含义,就是它之前的数据带来的状态更改都包含在当前对应的这个checkpoint里边,而之后的呢,就包含在下一个checkpoint里边。这就是分界线的含义。啊,所以这就是flink检查点算法里边非常重要的一个概念,也是我们实现分布式快照的一个基础。
我来说两句