00:00
我们已经了解了状态一致性的概念和级别啊,那我们知道在实际应用的过程当中,当然是最希望去做到精确一次once这样的状态一致性保证啊,那最后的处理结果肯定是正确的嘛。前面我们也说了,这里有两个关键点,一个就是当前我们读取的数据源应该能够重放数据,保证数据不丢啊,那另外还有一个呢,就是内部要开启检查点啊,我们利用这样一个checkpoint的机制,就可以保证发生故障进行回滚之后,所有的数据只被处理一次。那这个过程大家可能还稍微有一点疑惑啊,就是说诶这个感觉稍微有点不对啊,那就像之前我们这个从检查点恢复状态的时候,之前保存检查点之后啊,有一些数据,有可能我们这里边已经做过计算了,他已经读取进来,然后后面已经进行了统计了,然后你恢复状态之后再去重新进行处理,重新进行重放啊读取处理,这不相当于又处理了一遍吗?你怎么能说它是只处理了一次呢?
01:06
注意我们这里说的并不是处理的这个过程只做一次,那这样的话你就重放数据,那一定会重新计算嘛,啊这个是没有办法避免的,我们要的是结果里边。对应的这个数据处理了一次,而且只处理了一次啊,就是比方说如果说啊,之前我们在处理到。Hello,这个数据的时候,哎,这个时候第一个节点分区这里直接挂掉了,那这个时候如果恢复之前的状态的话,那相当于在我们sum这个算子的状态里边对应的哈,这个数据就没有统计进来,如果没有统计进来的话,后边重放对应在它这个状态里边的统计体现也就只出现一次,这样的话就保证。计算一次,而且只计算一次,这是完全没有问题的。但是呢,我们就会想到啊,要这么说的话,这精确一次的状态一致性那就非常容易保证啊,哎,我只要开启检查点不就完事了吗?
02:03
啊,其实实际应用的时候没那么简单,因为我们只看到了flink内部状态的结果是正确的。那我们知道啊,Link本身它应该还应该要有一个输出啊。最终他得到的计算结果是要写入到外部系统的,给其他的一些外部应用去提供数据的,那假如说我们之前处理到中间的时候啊,没有做检查点保存的那些中间状态,然后对应的输出就已经写入到了外部的一些其他的存储空间呢。如果已经写进去的话,你后边如果再做回滚,再做重新处理,再写一遍,那不就相当于做了重复写入了吗?诶,所以我们会发现啊,在真实考虑这个应用场景的时候,不光要考虑到flink内部状态的正确,还要考虑到诶连接外部系统到底是否做了重复的写入。那完整的一个流处理程序,我们所需要考虑它的状态一致性啊,考虑它结果正确的范围应该就包括了起始的数据源,中间的flink处理系统,最后还有S任务,也就是写入到外部系统这样一步操作,诶,那整个完整的这个流程,如果说都能保证处理一次,而且只处理一次的话,诶,那这才是我们真正想要的exactly once精确一次的状态一致性保证,这就是我们所说的端到端的状态一致性。
03:35
啊,那端到端到底能够达到什么样的状态一致性级别呢?啊,那前面我们说过啊,这就相当于是整个串联在一起的三步操作。整个的流程到底达到什么级别,当然要看短板了。木桶原理嘛,诶,那。在这中间,假如最弱的一环,哎,比如说我们知道啊,如果读取数据源的时候,这个外部数据源它就根本不能重放数据,那很显然这个数据有可能丢嘛,那一旦这个数据有可能丢,那后面就不用考虑了,它的端到端状态一致性最多就只能达到at most once。
04:13
所以我们说端到端的状态一致性是取决于整个流程当中最弱的那个环节啊,那当然了,整体来看的话,假如输入源这一端啊,假如它可以重置偏移量的话,诶,那我们就可以直接让这个SS算子这里保存一个当前读取数据的偏移量,然后一旦发生故障之后,重置偏移量,重新读取重放数据就可以了,这样的话,那其实就至少能保证这个数据不会丢啊,所以。相当于如果想要达到at least once至少一次状态一致性级别的话。主要看。数据源是否能够重放数据就可以了啊,但是如果说想要达到端到端的精确一次状态一致性的话,那这个就比较复杂了啊,那首先我们最前面这里也需要能重放数据,其次呢,诶中间弗Li格的处理流程得开启拆框,另外还有这个think端输出到外部系统的时候也得有对应的保证,所以接下来呢,我们就来详细的说一说端到端的精确一次状态一致性到底怎么样去保证?
05:21
这是在我们实际应用当中,其实是最难做到,也是最想要做到的一个状态,一致性的语义啊。啊,那我们知道想要做到端到端的精确一次,那我们说有三个环节嘛,每一环节都得有保证,那我们就单独拆开来看吧,首先输入端这个就不用说了,必须要能够重置偏移量,能够重放数据,假如说不能重放数据的话,那数据就有可能丢,啥都不要说了,那就是at one。所以这是前提,必须能够重放数据,当然了,只要输入端能够重放数据,可以说我们整个这个系统啊,端到端就能够做到数据不丢了,就能够达到at least once,也就是至少一次的状态一致性语义了。
06:07
然后接下来我们就要看了,内部当然是开启link的检查点机制,最后最关键的就是要看输出端的保证。而对于输出端在写入到外部系统的过程当中呢,诶,最大的问题其实就是因为我们数据可以重放,所以假如之前没有保存在checkpoint检查点里边的那些数据已经它对应的输出结果啊,已经写入到外部系统的话,那之后重放的时候就相当于要重新计算,然后再写一遍啊,这个时候就相当于做了重复写入嘛,怎么样保证这些重放数据只被写入一次,哎,那这就是我们所要去考察的关键。这里就有很多理论性上的一些介绍了啊哎,那这里我们主要给大家介绍两种能够保证精确一次一致性写入的方式,那一种叫做幂等写入,另外一种叫做事物写入,那对应的这两种方式呢,都需要外部的存储系统。
07:11
有相应的支持啊,那link呢,也为这两种写入方式提供了一些think function的接口啊,那接下来呢,我们就分别来进行一个讲解,首先是幂等写入,幂等写入其实比较简单啊,前面我们说过这个幂等操作,像我们说这个UV啊,那UV那就相当于重复的数据来了之后,对我们后边写入的结果没有影响,哎,那统计的这个UV值那就没关系嘛,它在概念上的定义呢,其实就是说一个操作可以重复执行很多次,但是呢,只导致一次结果更改,也就是说相同的数据到来,或者说相同的操作去执行,后面就不再生效了啊,只有第一次起作用。那我们知道这个最经典的例子啊,就是比方说这样一个函数FX等于E的X次方,如果对它进行求导的话,我们知道它求导就是自己嘛,所以无论他做几阶求导,得到的都是自身,所以对它进行求导操作,这就是一个幂等的操作。
08:15
啊,那我们知道在数据处理领域啊,在这个数据结构里边,最经典的当然就是哈希map的插入操作了,我们知道哈希map里边存储的是key value,如果是同样的一个数据的话,哎,我们来了之后都是A是K,然后它的抗值一都要插入这样一条数据的话,那你插入了一次A1,把它这个value更新成一了,下一次如果再要更新成一的话。那我们知道啊,K就决定了当前它这个数据存放的位置,一是它存放的值,那你位置和值都一样,那就相当于没做更改吧。所以在这种场景下,我们是可以做到重复的写入是不会影响最终的结果正确性啊,啊,那当然了,这就需要我们写入的外部系统,它是类似于哈希map这样的k value,对啊,针对他的K啊,重复的写入其实是没有影响的,比如说我们在里边做了一个键值论的存储,哎,之前我们在介绍s function的时候啊,直接写入到的时候,一个K一个value,它如果是相同数据的话啊,那肯定不会有任何的更改啊呃,相当于最后存的还是同一个值。
09:28
那或者关系数据库,像MYSQL,我们也可以指定当前的primary key啊,那对应的key所存放的数据重复写入也是不会改变。这里需要注意的一点是,它所保证的这个一致性呢,其实是最终结果的一致性,为什么呢?因为对于这样一个幂等写入,在发生故障进行回滚的时候,中间可能会出现状态短暂的不一致。这是什么意思呢?就是比方说啊,我们一直在统计这个work count,然后不停的插入对应的值,那可能呢,一开始A1,然后A2。
10:07
统计了两个,又来了,这个时候做了一个检查点快照的保存,所以我们存放的内容是A2啊,检查点里面恢复状态的话,恢复的也是A2,然后接下来继续处理,又来了一个A3。然后挂掉了。挂掉之后我们会想到啊,如果这些数据都已经直接写入到外部的某某一个这个兼值存储啊,比方说就是red,所以我们看到red里边存储呢,它已经是123已经变化到三了。这个时候如果发生故障。重新读取检查点去做恢复的话,那我们会发现啊,它又跳回到了二。所以是123又跳回到二,然后再变成三,诶之后追上了发生故障之前的那个状态,然后接下来456就可以继续增长了,最终统计的结果是对的,但是中间会出现一个短暂的回滚不一致的情况。
11:04
啊,这就是幂等写入的一个状态一致性的保证啊,啊,那我们会看到它并不完美啊,首先就是说,呃,中间我们会遇到这样的一个短暂的不一致,另外呢,即使是考虑最终结果的一致性,那你还得要求外部数据库啊,写入的这个存储设备得支持这样的一个k value键值存储才行。所以幂等写入它的限制其实还是比较多的。
我来说两句