控制一个应用程序执行的主进程,也就是说,每个应用程序都会被一个不同的JobManager 所控制执行。
JobManager 会先接收到要执行的应用程序,这个应用程序会包括:作业图(JobGraph)、逻辑数据流图(logical dataflow graph)和打包了所有的类、库和其它资源的JAR包。
JobManager 会把JobGraph转换成一个物理层面的数据流图,这个图被叫做“执行图”(ExecutionGraph),包含了所有可以并发执行的任务。
JobManager 会向资源管理器(ResourceManager)请求执行任务必要的资源,也就是任务管理器(TaskManager)上的插槽(slot)。一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的TaskManager上。而在运行过程中,JobManager会负责所有需要中央协调的操作,比如说检查点(checkpoints)的协调。
Flink中的工作进程。通常在Flink中会有多个TaskManager运行,每一个TaskManager都包含了一定数量的插槽(slots)。插槽的数量限制了TaskManager能够执行的任务数量。
启动之后,TaskManager会向资源管理器注册它的插槽;收到资源管理器的指令后,TaskManager就会将一个或者多个插槽提供给JobManager调用。JobManager就可以向插槽分配任务(tasks)来执行了。
在执行过程中,一个TaskManager可以跟其它运行同一应用程序的TaskManager交换数据。
主要负责管理任务管理器(TaskManager)的插槽(slot),TaskManger 插槽是Flink中定义的处理资源单元。
Flink为不同的环境和资源管理工具提供了不同资源管理器,比如YARN、Mesos、K8s,以及standalone部署。
当JobManager申请插槽资源时,ResourceManager会将有空闲插槽的TaskManager分配给JobManager。如果ResourceManager没有足够的插槽来满足JobManager的请求,它还可以向资源提供平台发起会话,以提供启动TaskManager进程的容器。
可以跨作业运行,它为应用提交提供了REST接口。
当一个应用被提交执行时,分发器就会启动并将应用移交给一个JobManager。
Dispatcher也会启动一个Web UI,用来方便地展示和监控作业执行的信息。
Dispatcher在架构中可能并不是必需的,这取决于应用提交运行的方式。
此处ResourceManager不是Yarn的
1.1命令行中提交Flink任务,客户端会将StreamGraph进行算子链合并得到JobGraph
1.2 将JobGraph任务提交给Dipatcher
2.1 启动Jobmanager,一job对应一个JobManager
2.2 Dispatcher向JobManager提交job
3.1 JobManager将JobGraph转化为ExecutionGraph,有了ExecutionGraph.
3.2 Jobmanager知道任务怎么执行了,JobManager向(Flink的)ResourceManager申请slot资源
4. TaskManager启动,向ResourceManager注册Slots.(告诉Slot有哪些Slot空闲)
5.ResourceManager让TaskManager向JobManager提供Slots
6.TaskManager在slot里边执行任务
JobManager主要作用:
1. 接受客户端请求。
2. 划分任务。
3. 申请资源。
4. 一个任务对应一个JobManager
ResourceManager主要作用(不是Yarn的ResourceManager):
1. 管理集群中slot资源
2. 将有空闲插槽的TaskManager分配给JobManager
3. 如果ResourceManager没有足够的插槽来满足JobManager的请求,它还可以向资源提供平台(Yarn/K8s)发起会话,以提供启动TaskManager进程的容器
4. 终止空闲的TaskManager,释放计算资源
TaskManager主要作用:
0. 主要负责计算,干活的
1.工作进程,任务都在TaskManager上运行
2.TaskManager中有资源(Slot)
3.需要像JobManager进行交互从而进行资源的注册和使用
4.多个TaskManager可以交换数据
0.Flink任务提交后,Client向HDFS上传Flink的Jar包和配置
1.向Yarn ResourceManager提交任务,ResourceManager分配Container资源
2.通知对应的NodeManager启动ApplicationMaster,ApplicationMaster启动后加载Flink的Jar包和配置构建环境,然后启动JobManager(Dispatcher)
2.1.Dispatcher启动JobMaster
3.JobMaster向ResourceManager(Flink)申请资源
4.ResourceManager(Flink)向ResourceManager(Yarn)申请资源启动TaskManager
5.ResourceManager分配Container资源后,由ApplicationMaster通知资源所在节点的NodeManager启动TaskManager
6.TaskManager注册Slot
7.发出提供Slot命令
8.TaskManager向JobMaster提供Slot
9.JobMaster提交要在Slot中执行的任务
算子的并行度:一个特定算子的 子任务(subtask)的个数被称之为其并行度(parallelism)
整条流的并行度:一般情况下,一个 stream 的并行度,可以认为就是其所有算子中最大的并行度
并行分配的子任务(subTask),必须分配到slot上执行.
并行度优先级:算子地方设置并行度>环境并行度>提交时设置的并行度>配置文件中设置并行度
solt:执行一个独立任务(subTask/线程)所需要的计算资源的一个最小单元.
slot会将内存隔离开,每个slot之间的内存资源互不干扰.
但是Slot的CPU是不隔离的,因此每个taskManger的slot个数可以设置大于CPU核数,但是slot个数>cpu核数的话,会造成CPU轮转多个slot.因此:建议每个taskManager的slot个数设置为CPU核数.
TaskManager:是一个JVM进行.每个taskManger的slot个数限定了TaskManager的并发能力(换句话说:控制一个 TaskManager 能接收多少个 task)
flink默认是可以前后发生的不同子任务放到同一个slot里边,即前后子任务共享同一个资源.因为他们在用一个共享组里边
这样的好处是1.一个slot里边可以保存整个作业运行的管道(pipeline).如果没有设计数据重分区的话,数据在一个pipeline全部完成所有操作.就不会有数据跨slot,taskManager间传输,即减少了IO.–效率提升
2.假如某个slot挂了,只想当于减少了并行度,别的slot仍然可以完成任务.–健壮性提升
如下图所示.这种没有设置共享组,所有算子在同一个default共享组里边
但是我们可以通过设置共享组,使前后发生的任务不在同一个slot中. 因为flink只允许同一个共享组中的任务在同一个slot中.不同共享组的任务不能在同一个slot中.
如下图所示:
共享组代码:
public class testslot {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource<String> streamSource = env.socketTextStream("hadoop102", 9999); //此处没设置共享组,默认就是default共享组
SingleOutputStreamOperator<Tuple2<String, Integer>> resultStream = streamSource.flatMap(new FlatMapFunction<String, Tuple2<String, Integer>>() {
@Override
public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
String[] words = value.split(" ");
for (String word : words) {
out.collect(new Tuple2<String, Integer>(word, 1));
}
}
}).slotSharingGroup("共享组1")
.keyBy(0)//此处没设置共享组,默认跟前边 共享组1 在一个共享组
.sum(1).setParallelism(2).slotSharingGroup("共享组2");
resultStream.print().setParallelism(1);//此处没设置共享组,默认跟前边 共享组2 在一个共享组
env.execute();
}
}
执行计划如下:占用5个slot 1+2+2
不同的任务分配到不同的线程(每个线程跑在slot上)上执行,从而实现并行计算.
答:每个共享组的最大slot个数相加. 如果没有设置共享组,则所有算子在同一个default共享组中.(即算子最大并行度)
答:一个slot可以读取多个流数据.相当于多流占用同一个slot.一个线程处理A流中数据,空闲了也可以处理C流中数据.
如下图所示:C流箭头----->并不向下游广播,而是表示C中数据可以发往下游D中任意一个.
Flink 中的执行图可以分成四层:StreamGraph -> JobGraph -> ExecutionGraph -> 物理执行图
StreamGraph:是根据用户通过 Stream API 编写的代码生成的最初的图。用来表示程序的拓扑结构。
JobGraph:StreamGraph经过优化后生成了 JobGraph,提交给 JobManager 的数据结构。主要的优化为,将多个符合条件的节点 chain 在一起作为一个节点
ExecutionGraph:JobManager 根据 JobGraph 生成ExecutionGraph。ExecutionGraph是JobGraph的并行化版本,是调度层最核心的数据结构。
物理执行图:JobManager 根据 ExecutionGraph 对 Job 进行调度后,在各个TaskManager 上部署 Task 后形成的“图”,并不是一个具体的数据结构。
•算子之间传输数据的形式可以是 one-to-one (forwarding) 的模式也可以是redistributing 的模式,具体是哪一种形式,取决于算子的种类
One-to-one:stream维护着分区以及元素的顺序(比如source和map之间)。这意味着map 算子的子任务看到的元素的个数以及顺序跟 source 算子的子任务生产的元素的个数、顺序相同。map、fliter、flatMap等算子都是one-to-one的对应关系。
Redistributing:stream的分区会发生改变。每一个算子的子任务依据所选择的transformation发送数据到不同的目标任务。例如,keyBy 基于 hashCode 重分区、而 broadcast 和 rebalance 会随机重新分区,这些算子都会引起redistribute过程,而 redistribute 过程就类似于 Spark 中的 shuffle 过程。
•同一个共享组、相同并行度的 one-to-one 操作,Flink 这样相连的算子链接在一起形成一个 task,原来的算子成为里面的 subtask
•同一个共享组、并行度相同、并且是 one-to-one 操作,三个条件缺一不可
Flink 采用了一种称为任务链的优化技术,可以在特定条件下减少本地通信的开销。为了满足任务链的要求,必须将两个或多个算子设为相同的并行度,并通过本地转发(local forward)的方式进行连接
public class testChains {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//env.disableOperatorChaining();//全局所有任务链断开
DataStreamSource<String> streamSource = env.socketTextStream("hadoop102", 9999);
SingleOutputStreamOperator<Tuple2<String, Integer>> resultStream = streamSource.flatMap(new FlatMapFunction<String, Tuple2<String, Integer>>() {
@Override
public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
String[] words = value.split(" ");
for (String word : words) {
out.collect(new Tuple2<String, Integer>(word, 1));
}
}
}).startNewChain()//该算子之后开启一个新链 即断下不断上
.keyBy(0)
.sum(1).disableChaining();//断开该算子的上下任务链
resultStream.print();
env.execute();
}
}
一个流处理程序,到底包含多少个任务?
在StreamGraph中每个算子是一个任务,此时并没有合并.
client会对其按照(Operator Chains)任务链规则进行合并得到JobGraph(如下图所示).
通过JobGraph计算任务个数