00:00
好,那我们已经知道flink里边状态是什么了,那接下来呢,我们就来分分类,看看这个状态的具体表现形式是什么样的啊,那其实对于flink而言啊,状态大家注意状态这个看起来像是flink自己存着的一个数据,对吧?哎,那这个数据它到底是谁存着的呢?它就是某一个任务存着的,保存着的,所以说每一个状态它必须是跟特定的任务或者说特定的算子关联在一起的,就是我们在代码里边定义的那每一步操作对吧?它在里边有自己的一个状态,状态始终是跟它关联在一起啊,那我们如果要是说在使用的过程当中啊,你如果代码里边想要用到运行的过程当中,想要用到这个状态的话,哎,那大家想这个是不是flink,得知道你当前的这个状态,到底在我的这个内存管理机制里边,它的位置在哪里,然后它的类型是什么,对吧,我得明确的能够找到。
01:00
啊,然后也知道它的类型,应用我的这个底层的状态管理机制,把它做这个序列化,反序列化对吧?做读取写入啊,这样就可以用这个了,所以说在我们做这个状态使用的时候呢,必须算子需要先去在啊环境里面,相当于先要注册一下这个状态啊这怎么说这个注册状态呢?呃,后面我们在代码里边给大家看一眼就知道了,其实就是要相当于把这个状态定义出来,获取一下,在运营师环境里边获取一下这个状态的控制句柄,对吧,具体来讲就是给一个这个状态具体给一个名,然后呢,呃,就是在运行运行时上下文里边对吧?呃,给一个具体的名儿,然后呢,给它的具体的数据类型也要定义出来,这样弗link就能准确的找到,而且知道该怎么做了,对吧,指导类型的话,就知道内存里边怎么操作了嘛,啊那具体来分的话,Flink里边有两种类型的状态,一种叫做operator state算子状态,另外。
02:00
这种叫做k set,就是我们所说的分组的监控的状态,从字面上理解,呃,这个一看这种分配,这就是什么k set肯定就是KBY之后,对吧?啊,我们在那个已经有了键的定义之后啊,已经分组之后的那个流里边,你要再去定义状态的话,那应该就是一个k state了啊,那如果说我们是一般化的,你没有分组直接去定义状态的话,那就是operator state对吧?啊,所以这里边大家看算子状态啊,这个operator state它的这个状态的作用范围。大家可以认为是类似于那个变量的作用域对吧?哈,是是什么样的一个作用范围呢?啊,有同学说你作用域嘛,那不就是它自己定义的那个我们在代码里边对吧?一个代码块你定义在哪里,它它它就是作用在哪里呢?注意啊,现在这个状态可不一样,我们状态在代码里边的定义,那可是一个我们现在运行的时候是一个分布式架构,对吧?那你当时定义的时候,其实只是代码里边对它的一个说明而已,具体我们任务执行的过程当中,它是一个分布式执行的,哎,所以说接下来我们同一个任务,如果啊,有好几个这个并行子任务的话,那你会想到那是不是具体我们当前的这个状态,每一个并行的这个子任务里边都会有这么一块啊,就是有有这么一块内存去去存这个东西啊,对吧,它们互相之间这个其实是互相无法访问的,对吧。
03:27
呃,就除非是后面我们讲到有一种特殊的状态叫广播状态,对吧,你把这个所有的都统一成一样的啊,那正常情况下他们互相之间是不同的啊,那这里面就还会有一个问题,之前我们说过,在每一个并行的这个算子任务里边,假如说我们不做这个分分组啊,不做K败的话,那是不是相当于就是所有的数据,当前这个分区里边所有的数据来了之后,我当前任务访问都是同一块内存啊啊,所以现在啊,算子任务就是这样的,它的限限定范围是什么呢?就是当前的并行的这个算子任务,也就是说当前所有的数据来了之后,都能访问到同样的状态。
04:09
而这个k states呢,它指的就是说针对每一个K来做访问和维护,当前它的访问范围呢,就只是当前K,你就算是在同一个分区里边,之前我们不是说同一个分区有可能有不同的K吗?对吧?你即使在同一个分区里边,大家也可以认为按照K又相当于把这个内存做了一个划分,做了一个隔离啊,就相当于还是不同的K访问不同的状态,对吧?只访问自己的就OK了,好,那自然大家就能想到,实际应用的过程当中,我们要做开窗,要做聚合,都得先K,对吧?然后你接下来你要考虑的状态,那往往也都是跟分组相关,你你都是分了组之后讨论的,你不会讨论所有的对吧?啊,那所以我们也是一般应用的就是k state,这个更常用一点,后面我我们也是主要以介绍它为主啊好,那我们具体来讲的话,算子状态大家看这个图应该就会很明确了,我们这里边有两个并行的子任务啊,就是都。
05:09
都是TASK1对吧,这里边是它并行任务一,并行任务二啊,这样把它并行列在这里,然后数据呢,分别进入这两个并行的子任务,大家就会看到了每一个任务,如果我们当前这个当前这个算子啊,定义了一个状态的话,比方说这里边是一个reduce操作对吧?啊,那肯定就得有状态了,或者说我们一个命明白操作,你你这个状态是什么?就是我们要保存之前所有数据的最小值嘛,那这个最小值是谁的最小值呢?大家注意啊,当前就是只是当前所有我这一个分区,当前这个并行子任务接收到的所有任务的一个所有数据的一个最小值,因为大家看这里边所有数据,它都能够访问这个同样的状态,对吧?它这里边只是访问这这同一份状态而已,所以呢,状态对于我们同一个子任务而言,里边的所有数据而言是共享的。
06:05
而这里边他的这一份状态呢,跟另外一个并行的子任务而言,这个是隔离开的,对吧,因为他都跨了slot了嘛,甚至是跨了task manager了,你当然这两这两个它是不能直接去访问的啊呃,你你要做访问肯定是要做这个序列化对吧,要要做其他的这些传输了,有网络传输才能才能去访问的,所以大家要注意啊,算子状态是这样的一个作用域,那另外呢,呃,这里边再给大家说一下算子状态具体来定义,还有不同的,就是具体来讲还有不同的算子状态的这个类型啊,那首先大家看到啊,一个最基本的或者说最常见的算子状态类型是什么呢?就是list state列表状态,它的含义就是说把我们这里边所有的状态保存成一组数据的列表,对吧,就是所有的状态没关系,你都来了之后都往里放吧,我就是把它存成了一个列表而已啊,所以后边大家会想到啊,你要是想要去做调整的时候也就简单对吧?呃,你这个保存。
07:05
这时候怎么样呢?把列表再拼起来保存不就完了吗?呃,就是像我们后面讲那个要保存checkpoint,你要做容错容错管理的时候,那就把不同的那个这个片段拼起来就完事了啊,那后面你如果要是想要做这个恢复,假如定行度又调整了,原先是两部分,现在变成三三部分了,那后面是不是我还要再把那个list的再拆开,对吧?相当于你定义这样一个list的,呃,分配操作就完了,所以大家看这里面这个状态为什么要定义成一个列表呢?就是方便后续的我们这个调整管理,但是大家看到你这里边其实就没有那种更加灵活更加呃复杂的那种操作,对吧?它只有列表,那你说我想做一个map操作可以吗?我定义成键值对可以吗?啊,这里边没有,你就只能在列表里面自己再去定义了,对吧?啊,这个就就那么复杂了,它本身是不支持的啊,那除了这个列列表状态还有什么呢?啊,还有的其实也差不多,还有一种状态叫做联合列表状态,它基本上跟这个列表状态一模一样,它主要。
08:05
差别在哪呢?就在于故障恢复的时候怎么恢复啊,就是列表状态这边我们要是故障恢复的时候,我们说是直接把那个哎保存的时候拼起来对吧?呃,然后这个最后我们要去恢复的时候再把它打散啊就就就完了,如果说这个联合列表状态是什么呢?哎,它不是这样的,它在做这个故障恢复的时候,是把我们之前每一个呃,这个并行算子任务的这个这个状态相当于都保持了一份,对吧?然后接下来呢,把这个状态它是要动态的做一个重新调整联合列表状态嘛,就是最后再调整的时候,把这个状态所有的状态合起来,就相当于都要复制一份,然后我再调整,有点有点这个意思啊啊,这个用的比较少,大家大概就知道就可以了啊,那后面还有一个状态是广播状态,这广播状态的话就更好理解了,那就是说如果说当前我们这个有多个并行子任务,然后这个每个并行子任务我们这里边保持的。
09:05
这份状态里边的内容要求它都完全一样啊,那这种状态这是什么状态呢?这就是所谓的这里所谓的这个广播状态了啊,这种广播状态就是呃,它只应用在这个比较特殊的特定的这种场景,就是说我们当前命行子任务里边要用到的这个数,它是完全一样的,对吧?啊就比方说这主主要用在什么场景呢?可能这是类似于一个配置项,对吧?啊,那这个配置项大家可能就会想到,那你这个配置项何必要这么做呢?我直接从这个外部这个配置文件里边去读也是一样的呀,啊,对吧?啊,这个就是看具体情况啊,就是有哪种情况呢?就是假如说我们当前的这个配置项,它又是一个动态,比方说从一个流里边读取出来的动态配置数据,然后我们还想把它结合在当前的这个,呃,就是存盘,呃,状态保存这个机制,要把它结合进来,就是你故障恢复的时候,还要把动态的这个这个当前的这个。
10:05
呃,配置项也得也得恢复出来对吧,就假如说有这种特别需求的时候,这个可能是需要去用到广播状态的,一般情况我们肯定用不到对吧,因为你配置项都是固定的嘛,我们其实就是直接你从配置文件读,难道这个不简单吗?非常简单,因为它固定读进来就完事了,也不需要去去做保存对吧,都已经在文字文件里面写好了,只有在这种比较就是特定的场景下才会用到广播状态。啊,那另外还有一种就是监控状态了啊,控状态我们说说它其实就是K之后,大家看前面K基于哈希扣的重分区了,对吧?然后在后边的这个操作里边,假如说是我们K之后做的这个,呃呃,做了一个reduce啊呃,那接下来这里边我们做了一个这个聚合操作,那他的这个状态是要找谁的呢?注意我们之前K之后并没有考虑他的,他那个状态会把不同的那个三合并起来对吧?那都是当前ID,当前的这个传感器,只是找自己传感器温度最小的那个值啊,那所以这个过程其实是对每一个K都保存了一个自己的状态,所以大家看到我当前这个task啊,并行这个子任务,那经过K外之后这个哈西克重分区,可能这个,呃,这个粉色的,或者说这个蓝色的这个数据它来了之后,不同的K啊,都是在这个分区里边的,那这怎么办呢?针对每一个K都要保存一份自己独有。
11:32
的状态对吧?啊,那这个相当于是给它有一个隔离的这个内存空间了啊啊,那所以说这里边就是说我们相当于是为每一个K维护了一个状态实例,然后呢啊,具有相同键的所有数据可以共享这个状态,访问这个状态不同K的数据呢,即使在同一个slot里边,同一个task里边,分区里边,对吧?呃,并行任务里边也不能访问啊,所以说这个就隔离的会比较啊比较好,我们在做实际操作的时候呢,你一般做做聚合,做开窗,你都要先KY嘛,那接下来你当然就是按照这个我们把它划分清楚,你直接这个按照当前K去定义状态不就完了吗?啊所以一般用到的状态都是K的state啊,那后面我们就以这个为主要内容给大家做讲解啊,那k state底层它可以有,就是具体来讲又有什么样的一些具体的类型定义呢?主要有这么几种,哎,大家看这个比呃,Operator state。
12:32
就就丰富多了啊,因为确实operator state用的也比较少,我们这里边用的啊,你看可以直接定义直状态,哎,直状态这个就很好理解,Value state嘛,就是什么呢?我就要保存一个数,然后你那边还要给我说保存成什么列表,对吧,太麻烦了,我就要保存一个数而已啊,所以这里边我就可以直接保存一个value state,就把一个数存进来。完全可以的,那另外还有什么呢?当然还有列表状态,对吧?跟那个operator state一样,把一组数保存成一个列表,那接下来我这个读取和这个做checkpoint保存的时候,它就都是一个列表,然后另外还有所谓的map,它就是一个映射状态,就前面我们说的,假如说我想保存键值对怎么办呢?哎,没问题,我定义一个map set里边,它的这个保存形式就是一个K一个value,一个K一个value啊,那那这样的话就就完全没问题了,是吧?就看起来就我们想要用到的这个数据结构,一些集合类型,该用到的也都有了。另外它还有一种更加方便,或者说呃,更加呃,就是用途更广的一种状态,叫做聚合状态,这个状态叫什么呢?它就叫做reducing state和aggregating state,这两种状态又是什么意思呢?之前我们不是讲过增量聚合函数的时候有reduce function和aggregate function吗?啊,对吧,那那那个其实是。
13:54
Flink API底层common里边给我们提供的一个聚合函数,那这里边的这个reducing state和aggreating state,它的含义就是什么呢?就是相当于把数据直接保存,可以保存一个什么呢?保存一个聚合状态啊,当然了,你也可以就是说把它保存成一个列表对吧?啊,那往往我们最后其实就是只是把它保存成了一个状态而已,所以之前我们这个比方说直状态你要保存的时候啊,就是存一个数进来对吧?来了一个新数,存一个数,列表状态呢,来了一个新数,追加到这个列表后面,呃,加上一个数对吧?啊,那这个映射状态map state,如果说你来了数之我判断那个K,如果有的话更新对吧,没有的话KY6对放进去,哎,那这个聚合状态就特殊一点,它是来了一个数之后呢,就相当于直接调用了一下我们的那个reduce function或者ggrereate function,直接在之前聚合的基础上直接做聚合,直接叠加了,然后。
14:54
最后我就只保持一个聚合结果就完了啊,所以大家也会想到,那我们之前你做的那些reduce操作对吧?呃,包括我们那个萨呃命max,它底层是什么呢?底层其实就是这样的一个状态,对吧,一个聚合状态。
15:12
好。
我来说两句