00:00
我们已经了解了检查点的基本原理啊,怎么样使用检查点去进行状态的保存和恢复,在这个过程当中我们也一再强调了啊,最关键的就是保存的时间点,我们保存的时间点是所有任务都处理完同一个数据的时候,把他们的状态做一个快照保存。这看起来很简单,哎,就是一个存档和读档的过程嘛,哎,但是我们仔细想一想的话,在具体底层实现上,可能还有很多细节需要去考虑,比如说哎,我们这里是处理完同一个数据之后,保存当前的所有的状态,那那比方说啊,我们是一条流水线,本身处理数据就有先有后,那SS处理完,比方说我们当前处理完第五个数据的时候,我要做一个检查点当前快照做一个保存,那我做完这个状态保存的时候呢?数据会继续朝下游去流动,那我这个SS任务是不是就等在这儿了呢?我还可以继续做后边的操作吗?诶,自然我们就想到了,其实是可以的,没有必要等,我们只要明确的知道当前要保存的检查点到底是哪个数,后边要做一个保存,哎,那这个数处理完了之后,那SS就保存自己的嘛,保存完了之后该干什么干什么,继续读后面的数就完了,同样后边的每一步任务都是这样。
01:25
哦,我们当前只要知道要处理的这个数据已经处理完了,就开始保存,保存完毕之后呢,接下来还是该干什么,继续干什么。所以这里面的关键点就在于,我们需要让当前要进行检查点保存操作的时候啊,这个数据得带上一个标记。我得知道,就是这个数据处理完了之后,就要做快照了。那这么一想的话,哎,那这个实现也非常的简单,这就相当于我们要在当前的数据上边再加一个字段,盖一个戳,哎,告诉当前这个数据处理完成之后要做快照保存,但是这样一来呢,又有另外一个问题,因为link是一个分布式的集群,在分布式的场景下。
02:08
我们的每一个数据它进行处理的时候,它只会进入到一个分区啊,那其他的并行分区又怎么办呢?他们什么时候去做自己的快照保存呢?啊,比如说这里我们就认为不同的K进入到了不同的分区,当前的这个sum任务并行度变成了三。所以这个时候,假如说我们认为某一个哈,这个数据他带了一个戳,在处理完它之后,接下来就要做这个快照的保存了,那如果说hello只会进入到第一个分区的话,那第一个分区知道诶,我当前处理完哈了,需要保存当前的状态,当前状态是三。那另外的两个分区,我什么时候该去保存当前的状态呢?这就完全不知道了吗?数据不会进入过来,我们当然就没有办法知道保存的时间点了。
03:00
那怎么样解决这样一个问题呢?呃,一个简单想法就是,那我们这一个属性啊,这样一个要触发检查点保存的这样一个戳,那就不要盖到数据上,因为数据后边可能是要分配到不同的分区,只能进入一个,那我们干什么呢?就像之前的水位线一样,Watermark一样。基于当前的数据,但是不跟他直接相关,而是在它后边插入一个单独的数据结构,那这个数据结构呢,就是说明之前的所有数据都已经处理完毕了,现在要做一个状态的快照保存了。所以这样一个标志,这样一个特殊的数据结构,我们会发现啊,它其实就跟每一个检查点保存的动作关联在了一起,可以说是一一对应的啊,就是每看到这样一个标志,当前的任务就把状态要做一个快照保存,那它所对应的这个检查点里边保存的状态是处理了哪些数据呢?就是在他之前已经到来的所有数据对应的状态改变就已经保存在这个检查点里面。
04:08
而在它之后所有的数据呢,哎,那对应的状态就没有保存在检查点里面,所以如果发生故障回滚到这个检查点的话,它之后的所有数据都要做一个重放,重新处理,所以我们会发现啊,这样一个标志,就把前后不同的数据按照检查点是否做了保存分开了,它是一个分界线啊,所以这其实就是我们所说的在。Flink的底层检查点算法当中的一个核心概念就是所谓的检查点分界线,好在底层的实现里边啊,英文叫做Barry checkpoint的bury。它所起的作用,哎,我们可以认为也是插入到当前数据流里边的一种特殊的数据结构,就像之前我们之前所说的水位线啊,Watermark一样,只不过呢,它主要是要把数据流里边的数据前后要分开,按照当前的checkpoint检查点是否保存了对应数据的状态做一个分析。
05:13
这就是分界线的主要含义。那这样一个特殊的数据结构分界线,那又应该由谁去插入到当前的数据流里边呢?啊,这里的任务当然就需要job manager出场了。哎,我们看到John manager这里边它会有一个检查点的协调器,它起到中央调度,中央协调的作用吧。这个协调器就会定期的周期性的去向task manager发出一个保存检查点的出发指令,啊,那对应的呢,它还会带着一个数据,就是当前检查点的一个编号,一个ID啊,告诉当前我们要保存的是第几号检查点。Task manager收到指令之后,就会让自己上面所有的SS任务把自己的状态,也就是保存的那个偏移量,诶先做一个存盘保存,记录一下当前已经读到了第几个数据,然后在数据流里面。
06:12
插入一个所谓的检查点分界线,把barrier这个特殊结构由S任务直接插入进去,哎,所以这就相当于是在我们的数据里边,数据流里边,从源头上就插入了一个分界线。接下来呢啊,那分界线就会像正常的数据一样,随着当前的数据流向下游去进行流动,进行传递,那如果说遇到了下游有多个并行的分区子任务的时候怎么办呢?哎,那我们会想到了,它显然是要通知到所有的并行子任务,所以这个时候就做一个广播就可以了。就相当于会复制多份,同时传递给下游所有的病情。子任。那下游的任务呢,只要接收到对应的这个barrier,就知道我应该要触发当前检查点的一个保存操作了啊,因为只要接收到这个per,很显然之前的所有数据从数据源这里读进来的所有数据就都已经处理完了嘛,当然就可以做快照保存了。
07:15
所以我们看到整个这个过程当中其实都是并行不悖的,就是每一步任务,每一个并行子任务啊,每一步操作,它其实都可以各自为证,它保存快照的一个时间点就是以看到这个barrier这个分界线为准,而那比方说我们当前这个SS任务已经保存了自己的数据,把Barry朝下游传递了,那接下来他该该干什么,继续干什么,继续读取后边的数据就可以了啊,那在这之前,假如说啊,后边的map任务或者这个sum任务并没有收到barrier,那他也是该处理什么数据,继续处理并不影响收到barrier的时候就开始做快照保存,保存完成之后同样也是继续读取后边的数据,该干什么继续处理就可以了。
08:03
所以整个的处理流程其实都是按照数据流的处理过程依次执行的,就是遇到什么,遇到数据就处理数据,遇到barrier就开始保存快照,每一个并行的子任务都没有单独的等待时间,各自为政,并行不备。所以这就是flink底层去实现检查点保存的一个关键啊。那具体的实现就是引入了分界线barrier这样一种特殊的数据结构。
我来说两句