如图所示,为Flink计算框架架构,在这里的架构指的就是Runtime 部分,也就是Flink core
观察上图,我们不妨猜一下Runtime的作用有哪些?
- 提出疑问
- Runtime夹在资源调度和上层计算处理之间,必定存在交互,核心逻辑就是为上层Task分配底层的资源
- 既然这样,就牵扯到任务的调度,资源的分配,以及首先得提交任务
- 似乎就是这样,但我们需要考虑到容错性,也就是Task挂掉或者fail了怎么办?显然Runtime层需要实现此逻辑
- Runtime层组件介绍
- JobManager,也叫master,负责任务调度,协调故障恢复(使用checkpoint) ,可部署多个实现HA
- TaskManager ,也叫worker,执行数据流中的task,缓存和交换数据
- client:严格意义上,clientb不属于Runtime组件,他的作用是用来准备和发送dataflow(注意:这里并不是数据,而是流,也就代表过client对数据进行处理,详细流程在任务提交中会提到),发送过去,然后等待结果,就是这样枯燥
- 什么是DataFlow呢?
- 先从Flink流式计算引擎讲起,我们都知道,计算引擎一般由三部分组成,source transform sink,如下图所示,source是数据源,transform对数据进行转换,Sink负责输出,组件之间转换的数据就是流
Flink基础实际上就是流和转换,Transform来源于一个或者多个stream作为输入的operator,通过transform计算又产生N个result stream
以一段代码为例进行说明,如下图所示,Flink程序会被映射为DataFlow,包含了流以及operator,每一个dataflow由N个source开始,又流向N个sink,类似于有向无环图
Task
什么是Task? Task真正干活的单位,上文说到,Flink基础是流和transform,那么按照最简单的逻辑,每个operator都作为一个Task就好了,这样可以吗?
可以,但是消耗太大,我们知道,每个Task都需要起一个线程,对每一个operator都作为一个Task的话,缺点显而易见,线程之间的切换需要消耗大量资源,以上图为例,假设source并行度为100,map也是100,keyby为100,sink为50的话,就要起350个线程,是否有优化的空间呢?
Flink将代码中可以优化的算子优化成一个算子链,如下图所示,简单来说就是在可以优化的算子包装起来,放到一个Task中,下面这个需要多少个线程呢?100+100+500=250,减少了150个线程,大大提高了吞吐量,同时也降低了延迟。那么问题又来了?合并成算子链条件是啥?我把所有算子都合并成一个算子链不就行了?
显然是不行的,是由以下条件的
- 上下游算子并行度一致,这点很好理解,source并行度为100,map是50,如何合并?
- 下游节点的入度为1
- 上下游节点都在同一个slot group中
- 下游节点的chain策略为always,map flatmap filter默认是always
- 两个节点间的分区方式是forward
- 用户没有禁用chain
那么问题又来了,你说的倒是很清楚,slot又是什么鬼?莫慌,知识都是环环相扣的,继续为大家讲slot是什么
Task slot和resource
接上文,先捋以下关系,operator放在算子链中,一个算子链就是一个Task,Task呢实际上放在Task slot中,Task slot可以放很多个Task 而TaskManager又包含多个Task slot,一环套一环的关系。不理解?看下图就明白了
一个TaskManager也就是一个节点,一个节点代表一个进程。
搞清楚了层级关系之后,我们再来讲slot
- slot是干嘛用的?
- slot的特点就是共享CPU,但是内存隔离,这样做的好处有以下几个方面
- 举个简单例子,Flink计算真正耗资源的在于shuffle算子,牵扯到数据的重分区,使用slot以后,由于slot CPU是共享的,所以耗资源的task就可以和耗资源较少的Task放在一起,提高了资源的利用率。
- slot是一个静态概念,代表的是执行并发的能力