00:00
现在大家已经知道一个flink代码啊,这个我们直接提交任务啊,提交起来之后,大家可以知道它到底要占据多少个slot了,但是我们还有最后一个问题就是。那一个弗link代码写完了之后,它到底应该生成多少个任务呢?哦呃,我们已经知道了它这个并行度设置啊,呃,之后我们可以知道这个slot需要资源的数量,但是前面我们在定就是看到它的那个执行结果执行计划图的时候,大家其实会发现啊,他跟我们一开始写出来的那个代码里边的每一步操作好像并不完全是一一对应的。并不是每一步操作就对应着一个任务,对吧?哎,那到底这里面又有什么制定的规则,或者说一些关联关系呢?啊,那接下来我们就要给大家讲解。其他的一些问题啊,首先我们要来讲一下这个程序与数据流,就是所谓的这个data flow的概念,那我们就要从自己本身写出来的flink代码讲起了,大家看一下这个fli代码的这个写法格式啊,它其实整体来讲的话,我们这里边的数据都是一个,就是如果是流式处理的话,都是基于data stream去做转换对吧?诶都是不停的这个data stream啊,首先我们env,然后去读取数据源,得到一个data stream,然后接下来是不是data stream可以去叫调各种各样的这个API去做转换操作啊,诶各种各种转换,然后大家看这里可以map,然后可以去做什么key之后开窗,然后apply,对吧?呃,然后最后还有一步就是。
01:39
我们可以把它输出到一个外部系统啊,啊,不管是前面我们在代码里面实现过的print,大家想print是不是也是一步输出。你看我们那个时生成的执行计划图里边,最后print到标准控制台输出是不是也是一步任务啊,对吧,也是一个一个操作啊,所以这就是我们最后的输出到外部系统的一步操作,或者你也可以right s csv是不是输出到文件啊,或者你输出到一些其他自定义的一些呃,数据库,或者说输出卡不卡是不是都可以啊啊,所以这就是flink程序的一个基本结构,它主要分成三大部三大块。
02:17
第一步是S,就是哎弗link去有一个专门的S任务,负责读取,从外部读取数据源。然后中间的叫都通通的都叫做transform transform呢就是啊,就是做转换计算对不对啊,大家看跟Spark相比的话,这里边我们并不区分转换算子和行动算子对吧?中间针对这个数据流做的所有操作我们都叫做一个转换。这样的一步操作对吧?呃,都叫做transform或者transformation,那最后还有一步就是think对吧?Think的话就是负责把当前最后计算的结果输出到外部系统里面去,哎,那大家想到所有的这一步一步操作串成一串连接起来是不是就是一个完整的数据流图啊,哎,所以大家看基于这样的一个就是我们代码里边的一步一步的操作啊,Source transform到最后的S,其实就可以映射画出这样的一个数据流图。
03:24
它就会包含我们的这三部分。然后一般情况啊,在这个弗林格代码里边,它生成的数据流图呢,都会以一个或多个S开始,大家想为什么是一个或多个呢。这是不是就是我们前面说的有可能有多条流啊后对呃双流,然后后面我做draw draw对吧,或者做一个连接,然后把它这个合并在一起再去做操作,这完全是可以的啊,那所以它可以有多个S,然后最终经过转换之后,以一个或多个thinkin结束,大家想这个think也可以有多个吗?诶,当然可以啊,你前面这里边处理的得到的这个结果是不是我可以把它,诶做一个控制制打印输出也可以,同时是不是写入到卡夫卡,写入到这个写入到MYSQL里啊呃,所以这些其实我都可以单独去定义,所以大家想那后边你如果有多个输出,是不是这后边就岔开了呀?啊,所以最终我们画出来这就是一个dag对吧,有效无环图就是这样的一个概念。
04:26
那所以大家可以看到,大部分情况下,我们的这张数据流图里边每一个任务啊,都跟前面我们定义的那个转换运算,或者说这个s think的这个运算是不是都是一一对应的呀,有一个运算,这里边就对应着一个框,一个任务,但是其实大家发现了,这里边是不是还有一些特殊的场景,你看这里边这个很复杂啊,这里面是不是有很多步骤它都合并在一起了呀。哎,那所以这就还涉及到其他的规则,就是理论上来讲是一个代码里边的运算的操作,就对应着一个任务,但是在有些场景下呢,它可以合并啊,那我们接下来再看一看啊,这就涉及到了我们在处理过程当中,要基于最初的数据流图,还要做一些转换变化,最终才能得到要执行的那个结果,那这个转换变化的过程呢,大概可以分成这么四步。
05:24
这就是从最初的数据流图,我们有时候直接把它叫做stream graph,对吧,有时候也就叫data graph对吧,就是一个数据流图啊,然后得到的是一个job graph。Stream graph的话就是我们一开始啊,大家调那个API get API,然后根据代码最初生成的那个图,那其实就是一步操作,就是一个一个节点,一个任务,对吧,然后基于它呢,在客户端上首先就要先做一个job graph的一个一个生成,那这个job graph有什么特点呢?他就针对前面的这一个数据流图做了一个优化,把前后发生的一些操作,如果要是满足一些条件的话,它直接就合并在一起,合并成一个大的任务,合并成整个的一个任务了,这就是我们看到的串在一起的那种任务,对吧?啊,那那得到的这个结果就叫做drop graph drop graph呢,接下来又会提交给job manager。
06:25
大家就想起来了,Job manager,是不是根据它可以生成一个真正可执行的并行化的那个版本啊,哎,那那个就叫做执行图execution graph,对吧,这个概念非常重要,这就是最后。转班要分发给。Task manager最终要执行的那个版本了啊,那最终那个,呃,Task manager呢,又会把这个转换成一个所谓的物理执行图啊,这个其实我们就一般不关心了,对吧?它其实并不是一个具体的数据结构,呃,其实它就是它最终在做一个根据自己最终执行的那种呃,条件啊,再做一些相对应相对应的转换,其实本身的逻辑都已经不变了,所以我们最关注的其实就是这个job graph和这个execution graph,那么用一张图看一下它的转变过程。
07:14
大家可以看到最初那是不是就是有一步操作,这就是一个对应的一个任务啊,对吧,大家看这个source flat map,然后后面又有一个呃,Kid aregation,那大家想我们之前不是有那个some嘛,Some是不是先做KBY啊,对吧?KBY之后做some啊,这里是一个kid agation,然后最后是think。啊,那这里大家要注意一下,就是K败,我们明明也是当时调API的一步操作啊,为什么这里面不是一个一个任务呢。这就是之前给大家讲到的k buy并不是一个计算操作,大家想KBY其实干了一件什么事儿,对,按照当前K的哈希code做了一个重分区,对吧?哎,这就是我们说的前面这步操作是flat map,那接下来假如说我要按照那个哈希code重分区之后做sum计算了,那我当前这个数据。
08:08
诶,大家想那个我流失计算不是这个,这个数据在当前这个slot上运行完成之后,我不是要传递到下一个slot上吗?下一个要执行的那个任务上去吗?那到底那个任务是在哪个slot哪个分区呢?那是不是我要根据K做一个计算啊,啊所以大家看这个KBY,你要说它有计算,它其实是不是就算了一个当前K哈希值啊,然后根据那个哈希值确定我当前对应的那个诶slot到底是哪一个分区,对吧?啊但现在我们就可以把这个每一个slo是不是当成一个分区了,对吧?一个slot它其实就是一个执行这个线程的一个一个资源的集合嘛,啊那类似于就是我们一个分区的概念,那所以接下来我确定了它属于哪个分区,那就可以把它直接传递到下一个分区上的那个任务,那那个任务是干啥。那个任务其实就对,是不是直接做萨姆就完事了,所以大家看sum是真正执行计算的任务,而KBY其实只是做了一个一个重分区对吧?啊基于哈code的重分区,所以大家看这里边我们的关键步骤其实就是叫做一个kid的applicationreg啊,就是分区之后根据这个键键啊进行分区之后的一个聚合,对吧,只是做了这个操作。
09:24
这就是最初的四步操作,然后接下来啊,当然它有这个对应的并行度,对吧,一开始我们不做拆分的话,就是四步操作,然后接下来呢,诶大家看它就首先在client上客户端上把它做了一个基本的优化,合并成了一个job graph,这里边做的主要优化是干了什么事,大家看。是不是把后边某满满足某些条件的任务就串在一起,合并成一个大的任务了,诶直接就把它这个变成,现在就变成三步操作三个任务了,对吧?然后再下一步呢,客户端是不是要把这个job graph连同我们那个抓包提交给job manager job manager,拿到job manager呃,Job job graph之后,是不是要把它拆成一个可执行的并行化版本啊,所以大家看这个就叫excu graph执行图。
10:14
它的这个特点大家看拆,拆开当前并行度是二,那是不是就要拆成两个啊,并行度是二,都拆成两个,然后接下来它们之间从前面这个source到flat map,怎么样去做这个数据传输,大家看这里边是不是都有对应的这个规则啊,诶,这就是一个可执行的版本了,最终把这个执行图传递给task manager task manager是不是就可以得到那个物理执行执行图就可以做计算了啊,所以这个物理执行图其实跟前面这个直行图已经非常的相似啊,这个我们一般也就不去考虑了,主要就是知道这样的一个直行图就可以了。这就是关于这个呃,代码啊,最初的一个代码啊,到最后生成执行图的一个过程。
我来说两句