00:00
接下来要介绍的是本书的第十章flink当中的容错机制,在前面第九章状态管理,状态编程这一部分其实已经有所涉及了,我们知道对于flink而言,所有的状态我们都应该要周期性定时的去做一个快照,持久化保存,这样的话才能在发生故障的时候把它恢复出来。这是一个。状态管理机制当中非常重要的一部分,也是之前我们提到所谓的checkpoint检查点它的核心功能,那其实我们知道对于容错保证而言,很多对于稳定性要求高的系统都是非常重要的,对于流式处理系统而言更是如此,因为我们知道流式处理的过程它是无休无止的,一直要持续运行。那但凡是机器,我们知道它不可能永远不出错,不可能无休无止的永远按照我们的要求运行下去,所以不管怎么样吧,有可能是因为。
01:06
程序发生发生了异常者,有可能是机器硬件发生了故障啊,那有甚至有可能是断电掉电啊,或者是其他的一些不可控的因素,都有可能出现当前任务中断,某个节点发生故障这样的一些情况,如果说我们只依赖一台机器进行的话,那当前节点中断了啊,那自然整个任务就被迫中断了。当前我们的处理方案是什么呢?啊,一种方案是高可用ha,而另外一个思路呢,当然就是分布式,用多台机器组成一个集群,这样的话其实我们就没有一个所谓的中心节点,一个挂了之后没关系,我们重启之后剩下的部分还可以组成一个集群,还可以继续运行,这样的话就解决了单点故障的问题,当然了,本来分布式的架构更多的是为了解决我们数据量非常大的时候这个并行处理的问题啊。呃,同时其实把。
02:07
容错的这一部分的单点故障问题也就解决了,这样的话,我们整个系统的稳定性和可用性有大大提高。在分布式的架构里边啊,我们现在其实如果发生故障的话,自然就想到了并行的有好几个节点都在运行,如果发生故障的话,哎,那没关系吧,我当前一个节点发生故障,那我就重新启动,如果它真的启动不了的话。就把当前的并行度相当于调小一点,然后再重新执行不就完了吗?之前我们所说的重启之后状态再重新分配调整,也就是基于这样一个架构来考量的啊,那看起来好像非常的简单,但是是事实上如果说我们要考虑每一个细节点的话,到底怎么样去做状态的快照,发生故障之后又怎么样把它恢复出来,其实还要有很多非常精巧的设计。
03:06
那么在flink里边呢,也是有一整套完整的机制来保证的,这就是我们所说的容错机制,保证发生故障之后怎么样恢复出正确的状态,那里边的核心当然就是前面我们已经提到过的检查点了。检查点的概念我们其实都已经非常的熟悉了,什么是检查点呢?就是当前所有状态的一个快照,持久化的保存嘛,所以如果要类比的话,这就相当于我们在玩游戏时候的一个存档而已啊,或者说我们在写论文,在打开一个word文档的时候,编辑了很多文字啊,那应该要定期的去做一个存盘,那假如说我们要是没有存档,没有存盘的话,一旦断电,或者说一旦要是游戏退出,那之后可能我们就只能从头来过了,这个是非常让人头疼的一件事情,所以养成随时存盘的好习惯,当然是解决发生故障,解决系统稳定性的最好的方法。
04:07
所以在流处理里边也是一样,我们的存盘,我们的存档就是检查点,就是checkpoint。那如果说我们已经把这个所有的状态都已经保存到检查点了之后,遇到故障重启的时候,那就需要的是独挡把。之前的检查点,我们已经保存的那个状态,再读取出来,回退到之前的某一时刻,然后继续进行,所以我们就发现了检查点其实就是flink容错机制的核心。这里面所谓的检查,其实就是要。保证检检查我们故障发生,故障恢复之后的这个处理的过程,最后处理的结果,检查它如果跟发生。就是没有发生故障,最后的结果是完全一样的话,这样的话就能保证我们结果是正确,所以有时候又会把checkpoint叫做一致性检查点。
05:10
接下来我们就来详细的考察一下,整个检查点保存的原理应该是什么样的。检查点的概念和基本的思想我们都已经非常的明确了,它就是一个存档吧。那这里面有一个关键的问题是,我们当前是一个分布式的系统,有很多个并行的节点,很多并行的并行的任务。他们每一个都有自己的一份状态,但现在如果说我们要去进行存盘存档的话,他们就是把当前这一时刻的所有状态都保存下来吗?诶,最理想的情况下,当然应该就是随时保存啊,那就是说我当前发出一个指令之后,那就应该是把当前的所有状态啊,就在这一时刻同时全部彻底保存下来啊。
06:02
但是这个直观上来看的话,好像是不能做到那么的,因为我们当前是由job manager去发的,发给每一个task manager本身网络传输就有延迟,所以我们不能做到严格意义上的同时。那这里面就涉及到了每一个task manager,那应该什么时候去做保存呢?如果说我们想到类似于游戏存档,或者说类似于这个word文档的存盘的话,那自然会想到我应该是。诶,我做完一点操作就应该保存一下,做完一点就保存一下,就是从流式处理的角度来看,那应该是每一个数据处理完了之后,当前就应该保存一下,保存存盘一下,那这样的话,当前数据保存的结果我就不会丢掉了。这是一个基本的想法。但是嗯,这种做法在实际的执行过程当中肯定是不够高效的,因为我们现在的数据是海量数据,大数据处理数据可能特别特别多,但那所有的数据来了之后,我每次处理完一条数据,马上就要做一个存盘啊,比方说我简单的前面有一个map任务。
07:15
假如他还有一个状态的话。我们把它这个map任务本来是无状态的啊,自己定义的状态,那么在这个过程当中就是非常简单的一个操作,过来之后,我也要去保存一下当前的状态,这显然是不划算的啊,在这个过程当中,每一个数据数据量非常的大,我们要做的存盘的操作就会非常的多,大量的性能就会耗费在做这个存盘的。过程当中啊,那我们的任务,我们的资源可能就没有办法应用在业务逻辑的处理上。那所以这种方法不能直接去使用。我们这里有一个问题,就是到底什么时候来做这个检查点的保存呢?因为我们现在是一个分布式的系统,当前有很多个并行的子任务。
08:08
有很多个不同的节点,当前同一个manager发出指令之后,那不同的task manager它可能有不同的响应。在最理想的情况下,我们应该是,不管是谁,不管是任何一个task manager,任何一个并行子任务,那都应该是处理完一个数据就应该保存一下当前的状态,这就是我们所说的随时保存。这样的好处在于,假如说当前我们发生故障了,那发生故障的话,那就把之前已经存盘的,呃,之前已经存盘的数据,那就是当前任务已经处理完成,计算,计算好了的嘛,我们就把它的结果拿出来,恢复之前的状态,那如果正在处理的数据,或者说还没有处理的数据,那就把它再重新重放一遍,再重新处理就完了,相当于就可以获得最低的延迟,最快速的衔接上我们之前故发生故障之前的状态,这样的话,看起来就是最完美的情况。
09:12
但是啊,尽管这样能够做到够快,但是呢,我们就需要针对每一个数据到来了之后,计算完成之后都要做一个存盘这样的操作,这个过程是比较耗费时间和耗费资源的,如果说我们当前是一个大数据处理吗?如果说有很多的数据同时到来的话。那光是制作保存检查点,做这个持久化保存就会耗费大量的资源和时间。那我们正常的数据处理就会受到影响。那所以我们就会想到这样不划算,尽管发生故障之后可能恢复起来比较快,但是我们正常正常情况下,一般情况怎么会发生故障呢?更多的时间我们应该用来做这个正常的数据处理吗?所以我们就想到了可以借鉴之前walmark的生成机制,而我们之前说本身也是按道理是每来一条数据我们就生成,以当前的这个时间戳啊进行更新,然后生就可以了,但是呢,这样不够高效,怎么样能够更高效呢?
10:21
周期性的去做一个触发保存。所以我们现在的这个做法,就相当于是像word或者是一些游戏里边给我们提供的自动存档的这种方法,那我们知道自动存档的话,它肯定不可能是我们每做了一个非常简单的操作,鼠标移动了一下,它马上就给我们做保存啊,也不会是我们在word里面每改一个字马上就做保存,它其实是要检测到我们当前发生了变化,而且是隔一段时间周期性的去保存一下就可以了。这样的话。就会,呃,相当于是对于我们当前的时效性和。
11:03
资源的占用做一个权衡啊,当然它的代价就就在于我们当前是每隔一段时间做一个保存嘛,但那所以在两次保存这一段时间内,有可能会有很多个数据,其实已经也是做了,做了这个计算的得到结果了,但是这个结果没有保存起来啊,那所以接下来就相当于这一部分要重放数据,然后重新做计算了,看起来做了一点无用功。但是我们知道这个代价是值得的,这一部分的延迟其实我们可以在海量数据的情况下可以忽略不计,那所以在很多场景下啊,我们。是可以接受这样的处理方案的,弗link默认的方式也就是周期性的去进行一个存档。
我来说两句