00:00
那回忆一下,在flink里边,我们想要保证exactly ones精确一次的状态执行语义靠什么来保证呢?啊,前面其实我们也已经说了,那其实就是容错机制的核心,是不是就是拆po米啊,那检查点啊,我们说检查点它主要用了一个什么样的处理方式呢?就保证了这个状态一致性,是不是就是它保存的是所有任务状态的快照,对吧?这个快照它选取的时间点非常的巧妙,刚好是所有任务都处理完同一份数据之后的那个时间点,我去把它做一个保存,所以接下来呢?呃,另外就是他还要求是不是我们那个呃,当前的。源就是SS任务那里要保存一个那个偏移量之后,可以重新提交偏移量对吧?所以它保存下来的这个当前的检查点是不是要不就包含之前的所有的数据对吧?啊,那之后再来的数据是不是就都没包含在里边啊,那接下来是不是我如果要是重新恢复了之后,把那个偏移量重新提交,接下来的数据是不是就是挨个重放就对了。
01:06
因为当前检查点里边是不是在保存检查点之后的那些数据的那个那个状态其实都没保存进来啊,啊,所以这个问题就直接就解决掉了,对吧?啊,所以状态一致性检查点就是所谓的故障恢复机制的核心,也是我们整个弗林克内部状态一致性保证的一个核心。啊,那具体的过程的话,大家回忆一下,就是当前这个例子啊,我们都是处理完五这个数据的时候,奇数求和偶数求和的状态,一个是六,一个是九,把它对应的保存在当前的checkpoint里边,那如果后边六和七继续处理的时候。大家注意六和七处理的这个过程当中,没有新的checkpoint了,对吧?哎,那然后就挂了,挂了的话,六和七是不是接下来我重新处理的时候就要重放啊,哎,那大家说,那假如说像前面我们的这个例子,六已经加进来了,七没加进来,那那这个这个状态会不会六就呃六就多加了一次呢?或者说七就丢掉了呢?啊,我现在既然要重放,是不是肯定都不会丢啊,那六是不是重放了之后就会就会重新叠加呢?
02:15
诶大家发现不会,因为是不是这个状态,这里是十二六加了之后确实是变成12了,但是我们拆po的恢复之后,是不是又回滚到六了呀,又回滚到了六,没有被计算的那个状态,接下来是不是就绝对最后的结果是精确一次。只加一次对吧,不会丢,而且只计算一次,这就是所谓呃,Checkpoint一致性检查点对我们计算结果的保证,呃,那大家现在知道在内部做这个一致性保证的话,只要有checkpoint应该就搞定了,呃,大家发现就是只要有checkpoint,那我就能保证,呃里边的这个数据就应该是在万S对吧?啊,精确一次啊,不会丢,也不会这个重复处理,但是其实大家会发现,如果说我这这个所谓的在6万S只是针对弗林克内部而言的。
03:06
就是如果数据正常情况啊,我这边还能来的话,那接下来我这个既不会丢,也不会也不会重复处理,那假如说大家想我前面这个就没办法重新提交偏移量,你像我们那个卡夫卡是可以提交的,对吧,那假如说我们是S的文本流呢,那里是不可能保存之前数据的,也没有提重新提交偏移量这一说,那大家想是不是你这里边回滚到五,那六和七是不是丢了就丢了呀,真的就没了对吧?哎,所以大家就会发现,如果要是考虑到我们真实的应用场景的话。不仅仅是要考虑flink内部的保证,是不是还要考虑数据源和这个输出到持久化系统里边的这个SK这步操作啊,两边都得保证整个这个流程是精确一次,这个才叫真正精确一次,所以这种精确一次就叫做所谓的端到端状态一致性啊,就是我们要保证这个争取要保证端到端的exactly one状态一致性。
04:08
啊,那大家要考虑一下,那整个端到端的这个一致性级别取决于什么呢。是不是我只要内部flink有checkpoint,它内部保证这个exactly罐了,整个端到端我连什么系统都是exactly罐呢。其实不是对吧,前面我们已经说了,你如果外边连卡夫卡的话,前面那个数据不会丢,对吧,那如果连连so是不是直接就丢了呀。所以大家会发现当前整个端到端的一致性级别取决于什么?哎,对,这又是木桶原理对吧?最弱的那一环是不是就决定了我们当前整个链条里边的状态一致性级别啊啊,所以接下来我们如果想要实现exactly one这样最高级别的状态一致性的话,大家会想到应该怎么做,每一个环节都得保证数据不丢,而且只处理一次啊。那所以接下来我们就来说一下,首先是内部保证,这个非常简单,Checkpoint直接搞定了,那source端怎么样去保证呢?
05:12
哎,SS端的话其实非常简单,首先大家想到SS端,只要我是不是这个任务SS任务啊,跟外部系统连接起来之后,能够重置,重新提交偏移量的话,那是不是就相当于我之前的数据就都可以不丢啊。那然后大家想到,只要数据不丢,我SS任务这边不管它读取多少次,对我后边是不是没什么影响啊。大家想对于我我SS任务的这个状态有影响吗?我SS任务只存当前的偏移量对吧?哎,所以没有任何影响啊,呃,就这个有同学可能想到,哎,那不对呀,你之前这个呃,重新重置偏移量了之后,之前我读过一次六和七,现在又读了一次六和七,这是不是处理了两次呢?对,大家注意这个是状态回滚了对不对,我们要保证的是状态一致性,我们并不是保证它的操作要一致性,对不对。
06:07
就我们所说的,精确一次是最终的,状态是精确一次的,每一个数据是处理一次,而且只处理一次表现在状态上。那那中间我们的操作,假如说这个数据读了两次,如果最对最后的状态没影响的话,大家想是不是最后我们的状态还是一致的呀,对吧,你股状态之前回滚了呀,回滚到之前比方说五的那个偏移量了,那后边来了之后,六和七是不是相当于又是只读了一次啊,诶所以这个是没问题的,这就是SS端只要保证可以重设它的那个读取位置啊,重设偏移量就可以了。那首先这边这边如果能重设偏移量的话,大家想后边我的数据是不是肯定就不会丢了。对吧?啊,后面已经没有问题了啊,就是肯定这个数据至少是可以重新处理一遍了,然后接下来呢,就是think端了,大家想一下,Think端如果要是发生故障要做恢复的时候,首先它数据会不会丢呢?诶如果发生故障恢复了之后,你要怕它丢的话,是不是只要SS端那边重新提交编移量就可以了啊,就是那边只要前面每一步都保证了重新提交编移量,重新消费数据,然后一步一步传输,传到think端数据就不会丢,对吧。
07:19
哎,那另外还有一个问题是会不会重复写入呢?这个就比较麻烦了,因为大家想跟外部那个系统连接的时候,一般情况都是think端,我们是来一个处理一个吗?那是不是直接就写进去了呀。那如果说要是你下一次故障恢复重新启动之后,你之前中间的状态是可以回滚,但是你写入到外部系统,你能让外边回滚吗。这就得看其他的保证了,对不对,这得外部系统种支持才行,对不对啊,所以大家看到这种实现的话,在具体的应用当中有两种实现方式,一种叫做幂等写入,另外一种叫做事物写入,这就是具体保证端到端exactly one的具体的实现方式。
我来说两句