3、flink架构,资源和资源组
一、flink架构
1.1、集群模型和角色
如上图所示:当 Flink 集群启动后,首先会启动一个 JobManger 和一个或多个的 TaskManager。由 Client 提交任务给 JobManager,JobManager 再调度任务到各个 TaskManager 去执行,然后 TaskManager 将心跳和统计信息汇报 给 JobManager。TaskManager 之间以流的形式进行数据的传输。上述三者均为独立的 JVM 进程。
- Client:
- 用户在提交编写好的 Flink 工程时,会先创建一个客户端再进行提交,这个客户端就是 Clien。可以是运行在任何机器上(与 JobManager 环境连通即可,一般在跳板机上)。提交 Job 后, Client 可以结束进程,也可以不结束并等待结果返回。
- Client 会根据用户传入的参数选择使用 yarn per job 模式、stand-alone 模式还是 yarn-session 模式将 Flink 程序提交到集群。
- JobManager:
- 集群的管理者,负责调度任务,主要负责从 Client 处接收到 Job 和 JAR 包等资源后,会生成优化后的执行计划,并以 Task 的 单元调度到各个 TaskManager 去执行。
- 负责调度任务、协调 checkpoints、协调故障恢复、收集 Job 的状态信息,并管理 Flink 集群中的从节点 TaskManager。
- TaskManager :
- 实际负责执行计算的 Worker,在其上执行 Flink Job 的一组 Task;TaskManager 还是所在节点的管理员,它负责把该节点上的服务器信息比如内存、磁盘、任务运行情况等向 JobManager 汇报。
- 在启动的时候就设置好了槽位数(Slot),每个 slot 能启动一个 Task,Task 为线程。从 JobManager 处接收需要部署的 Task,部署启动后,与自己的上游建立 Netty 连接,接收数据并处理。
- flnik架构中的角色间的通信使用Akka(量小,数据大量传输时性能差),数据的传输使用Netty(量大,spark全部使用Netty通信)。
二、flink资源和资源组
在flink集群中,一个TaskManager就是一个JVM进程,并且会用独立的线程来执行task,为了控制一个TaskManager能接受多少个task,Flink提出了Task Slot 的概念,
- 我们可以简单的把 Task Slot 理解为 TaskManager 的计算资源子集。假如一个 TaskManager 拥有 5 个 slot,那么该 TaskManager 的计算资源会被平均分为 5 份,不同的 task 在不同的 slot 中执行,避免资源竞争。但是需要注意的是,slot 仅仅用来做内存的隔离,对 CPU 不起作用。
- 通过调整 task slot 的数量,用户可以定义task之间是如何相互隔离的。每个 TaskManager 有一个slot,也就意味 着每个task运行在独立的 JVM 中。每个 TaskManager 有多个slot的话,也就是说多个 task 运行在同一个JVM中。 而在同一个 JVM 进程中的 task,可以共享 TCP 连接(基于多路复用)和心跳消息,可以减少数据的网络传输。也能 共享一些数据结构,一定程度上减少了每个task的消耗。
2.1、task的并行度
val wordCount2: DataStream[(String, Int)] = socket.flatMap(new FlatMapFunction[String, (String, Int)] {
override def flatMap(int: String, out: Collector[(String, Int)]): Unit = {
val strings: Array[String] = int.split(" ")
for (str <- strings) {
out.collect((str, 1))
}
}
}).setParallelism(2) // 设置task的并行度/槽数
.keyBy(_._1).sum(1).setParallelism(2)
2.2、Operator Chains
为了更高效地分布式执行,Flink 会尽可能地将 operator 的 subtask 链接(chain)在一起形成 task。每个 task 在一个 线程中执行。将 operators 链接成 task 是非常有效的优化:
- 它能减少线程之间的切换;
- 减少消息的序列化/反序列化;
- 减少数据在缓冲区的交换;
- 减少了延迟的同时提高整体的吞吐量。
- 上下游的并行度一致(槽一致)。
- 下游节点的入度为1 (也就是说下游节点没有来自其他节点的输入) 。
- 上下游节点都在同一个 slot group 中。
- 下游节点的 chain 策略为 ALWAYS(可以与上下游链接,map、flatmap、filter等默认是ALWAYS) 。
- 上游节点的 chain 策略为 ALWAYS 或 HEAD(只能与下游链接,不能与上游链接,Source默认是HEAD) 。
- 上下游算子之间没有数据shuffle (数据分区方式是 forward) 。
- 用户没有禁用 chain。
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.apache.flink.streaming.api.operators; import org.apache.flink.annotation.PublicEvolving; /**
* Defines the chaining scheme for the operator. When an operator is chained to the
* predecessor, it means that they run in the same thread. They become one operator
* consisting of multiple steps.
*
* <p>The default value used by the StreamOperator is {@link #HEAD}, which means that
* the operator is not chained to its predecessor. Most operators override this with
* {@link #ALWAYS}, meaning they will be chained to predecessors whenever possible.
*/
@PublicEvolving
public enum ChainingStrategy { /**
* Operators will be eagerly chained whenever possible.
*
* <p>To optimize performance, it is generally a good practice to allow maximal
* chaining and increase operator parallelism.
*/
ALWAYS, /**
* The operator will not be chained to the preceding or succeeding operators.
*/
NEVER, /**
* The operator will not be chained to the predecessor, but successors may chain to this
* operator.
*/
HEAD
}
代码验证:
- operator禁用chaining
- 全局禁用chaining
- 查看job的graph图
原理与实现:
那么 Flink 是如何将多个 operators chain在一起的呢?chain在一起的operators是如何作为一个整体被执行的呢? 它们之间的数据流又是如何避免了序列化/反序列化以及网络传输的呢?下图展示了operators chain的内部实现:
如上图所示,Flink内部是通过OperatorChain这个类来将多个operator链在一起形成一个新的operator。
OperatorChain形成的框框就像一个黑盒,Flink 无需知道黑盒中有多少个ChainOperator、数据在chain内部是怎么 流动的,只需要将input数据交给 HeadOperator 就可以了,这就使得OperatorChain在行为上与普通的operator无 差别,上面的OperaotrChain就可以看做是一个入度为1,出度为2的operator。所以在实现中,对外可见的只有 HeadOperator,以及与外部连通的实线输出,这些输出对应了JobGraph中的JobEdge,在底层通过 RecordWriterOutput来实现。另外,框中的虚线是operator chain内部的数据流,这个流内的数据不会经过序列化/ 反序列化、网络传输,而是直接将消息对象传递给下游的 ChainOperator 处理,这是性能提升的关键点,在底层 是通过 ChainingOutput 实现的
2.3、SlotSharingGroup 与 CoLocationGroup
Flink 允许将不能形成算子链的两个操作,比如下图中的 flatmap 和 key&sink 放在一个 TaskSlot 里执行以达到资源共享的目的。
每一个 TaskManager 会拥有一个或多个的 task slot,每个 slot 都能跑由多个连续 task 组成的一个 pipeline。
如上文所述的 WordCount 例子,5个Task没有solt共享的时候在TaskManager的slots中如下图分布,2个 TaskManager,每个有3个slot:
默认情况下,Flink 允许subtasks共享slot,条件是它们都来自同一个Job的不同task的subtask。结果可能一个slot 持有该job的整个pipeline。允许slot共享有以下两点好处:
- Flink 集群所需的task slots数与 job 中最高的并行度一致。
- 更容易获得更充分的资源利用。如果没有slot共享,那么非密集型操作 source/flatmap 就会占用同密集型操作 keyAggregation/sink 一样多的资源。如果有slot共享,将基线的2个并行度增加到6个,能充分利用slot资源, 同时保证每个TaskManager能平均分配到相同数量的subtasks。
我们将 WordCount 的并行度从之前的2个增加到6个(Source并行度仍为1),并开启slot共享(所有operator都在 default共享组),将得到如上图所示的slot分布图。该任务最终会占用6个slots(最高并行度为6)。其次,我们可 以看到密集型操作 keyAggregation/sink 被平均地分配到各个 TaskManager。
SlotSharingGroup:
- SlotSharingGroup 是 Flink 中用来实现slot共享的类,它尽可能地让subtasks共享一个slot。
- 保证同一个group的并行度相同的sub-tasks 共享同一个slots
- 算子的默认 group 为 default(即默认一个job下的subtask都可以共享一个slot)
- 为了防止不合理的共享,用户也能通过 API 来强制指定 operator 的共享组,比如: someStream.filter(...).slotSharingGroup("group1");就强制指定了 filter 的 slot 共享组为 group1。
- 怎么确定一个未做 SlotSharingGroup 设置的算子的 Group 是什么呢(根据上游算子的 group 和自身是否设置 group 共同确定)
- 适当设置可以减少每个 slot 运行的线程数,从而整体上减少机器的负载 CoLocationGroup(强制)
CoLocationGroup(强制):
- 保证所有的并行度相同的sub-tasks运行在同一个slot
- 主要用于迭代流(训练机器学习模型)
代码验证:
- 设置本地开发环境的slot数量
- 设置最后的 operator 使用新的 group
- 为什么占用了两个呢?
- 因为不同组,与上面的default不能共享slot,组间互斥。
- 同组中的同一个 operator 的 subtask 不能在一个 slot 中,由于 operator 的并行度是 2,所以占用了两个槽 位,组内互斥。
原理与实现:
那么多个 tasks(或者说 operators )是如何共享 slot 的呢?
我们先来看一下用来定义计算资源的slot的类图:
抽象类 Slot 定义了该槽位属于哪个 TaskManager(instance)的第几个槽位(slotNumber),属于哪个 Job(jobID)等信息。最简单的情况下,一个 slot 只持有一个task,也就是 SimpleSlot 的实现。复杂点的情况,一 个 slot 能共享给多个task使用,也就是 SharedSlot 的实现。
接下来我们来看看 Flink 为subtask分配slot的过程。关于Flink调度,有两个非常重要的原则我们必须知道:
- 同一个 operator 的各个 subtask 是不能呆在同一个 SharedSlot 中的,例如 FlatMap[1] 和 FlatMap[2] 是不能在同一 个 SharedSlot 中的。
- Flink 是按照拓扑顺序从 Source 一个个调度到 Sink 的。例如 WordCount(Source并行度为1,其他并行度为 2),那么调度的顺序依次是:Source -> FlatMap[1] -> FlatMap[2] -> KeyAgg->Sink[1] -> KeyAgg- >Sink[2]。假设现在有2个 TaskManager,每个只有1个slot(为简化问题),那么分配slot的过程如图所示:
注:图中 SharedSlot 与 SimpleSlot 后带的括号中的数字代表槽位号(slotNumber)
- 为Source分配slot。首先,我们从TaskManager1中分配出一个SharedSlot。并从SharedSlot中为Source分配 出一个SimpleSlot。如上图中的①和②。
- 为FlatMap[1]分配slot。目前已经有一个SharedSlot,则从该SharedSlot中分配出一个SimpleSlot用来部署 FlatMap[1]。如上图中的③。
- 为FlatMap[2]分配slot。由于TaskManager1的SharedSlot中已经有同operator的FlatMap[1]了,我们只能分配 到其他SharedSlot中去。从TaskManager2中分配出一个SharedSlot,并从该SharedSlot中为FlatMap[2]分配 出一个SimpleSlot。如上图的④和⑤。
- 为Key->Sink[1]分配slot。目前两个SharedSlot都符合条件,从TaskManager1的SharedSlot中分配出一个 SimpleSlot用来部署Key->Sink[1]。如上图中的⑥。
- 为Key->Sink[2]分配slot。TaskManager1的SharedSlot中已经有同operator的Key->Sink[1]了,则只能选择另 一个SharedSlot中分配出一个SimpleSlot用来部署Key->Sink[2]。如上图中的⑦。
最后Source、FlatMap[1]、Key->Sink[1]这些subtask都会部署到TaskManager1的唯一一个slot中,并启动对应的 线程。FlatMap[2]、Key->Sink[2]这些subtask都会被部署到TaskManager2的唯一一个slot中,并启动对应的线 程。从而实现了slot共享。
Flink中计算资源的相关概念以及原理实现。最核心的是 Task Slot,每个slot能运行一个或多个task。为了拓扑更高 效地运行,Flink提出了Chaining,尽可能地将operators chain在一起作为一个task来处理。为了资源更充分的利 用,Flink又提出了SlotSharingGroup,尽可能地让多个task共享一个slot。
如何计算一个应用需要多少slot:
- 不设置 SlotSharingGroup 时是应用的最大并行度,此时只有一个 default 组。
- 设置 SlotSharingGroup 时所有 SlotSharingGroup 中的最大并行度之和。
由于 source 和 map 之后的 operator 不属于同一个 group ,所以 source 和它们不能在一个 solt 中运行,而这里的 source 的 default 组的并行度是10,test 组的并行度是20,所以所需槽位一共是30
3、flink架构,资源和资源组的更多相关文章
- 十九、dbms_resource_manager(用于维护资源计划,资源使用组和资源计划指令)
1.概述 作用:用于维护资源计划,资源使用组和资源计划指令;包dbms_resource_manager_privs用于维护与资源管理相关的权限. 2.包的组成 1).dbms_resource_ma ...
- Flink架构分析之资源分配
Task Slot Flink中每个真正执行任务的TaskManager都是一个JVM进程,其在多线程环境中执行一个或者多个子任务.为了控制一个JVM同时能运行的任务数量,flink引入了ta ...
- flink架构介绍
前言 flink作为基于流的大数据计算引擎,可以说在大数据领域的红人,下面对flink-1.7的架构进行逻辑上的分析并和spark做了一些关键点的对比. 架构 如图1,flink架构分为3个部分,cl ...
- Flink入门(二)——Flink架构介绍
1.基本组件栈 了解Spark的朋友会发现Flink的架构和Spark是非常类似的,在整个软件架构体系中,同样遵循着分层的架构设计理念,在降低系统耦合度的同时,也为上层用户构建Flink应用提供了丰富 ...
- Flink架构和调度
1.Flink架构 Flink系统的架构与Spark类似,是一个基于Master-Slave风格的架构,如下图所示: Flink集群启动时,会启动一个JobManager进程.至少一个TaskMana ...
- Flink架构,源码及debug
序 工作中用Flink做批量和流式处理有段时间了,感觉只看Flink文档是对Flink ProgramRuntime的细节描述不是很多, 程序员还是看代码最简单和有效.所以想写点东西,记录一下,如果能 ...
- Flink架构及其工作原理
目录 System Architecture Data Transfer in Flink Event Time Processing State Management Checkpoints, Sa ...
- [C++] 将 mp3 等音乐资源以资源形式嵌入 exe 文件中
引用:http://www.easyx.cn/skills/View.aspx?id=6 本文讲解怎样将 mp3 等音乐资源以资源形式嵌入 exe 文件中,并通过 mciSendString 调用.嵌 ...
- 将 mp3 等音乐资源以资源形式嵌入 exe 文件中
引用:http://www.easyx.cn/skills/View.aspx?id=6 本文讲解怎样将 mp3 等音乐资源以资源形式嵌入 exe 文件中,并通过 mciSendString 调用.嵌 ...
随机推荐
- iOS 内存管理:从 MRC 到 ARC 实践
对于 iOS 程序员来说,内存管理是入门的必修课.引用计数.自动释放等概念,都是与 C 语言完全不同的. iOS 内存管理的核心是引用计数. 接触 MRC 时遇到最头疼的问题就是:为什么那么多 rel ...
- vue渲染src
- 活久见!Linux命令行居然也可以用来查看图像?
在 Linux 中有很多 GUI 应用程序可以查看图像,但是这对经常使用命令行来工作的人可能会觉得很繁琐.今天要介绍的是 3 个实用的 CLI 图像查看器来在终端上查看图像,让那些使用 CLI 的朋友 ...
- ubuntu上安装redis和配置远程访问
ubuntu上安装redis和配置远程访问 安装redis: 下载安装包: wget http://download.redis.io/releases/redis-4.0.1.tar.gz 解压: ...
- 简单分析ucenter 会员同步登录通信原理
1.用户登录discuz,通过logging.php文件中的函数uc_user_login对post过来的数据进行验证,也就是对username和password进行验证. 2.如果验证成功,将调用位 ...
- 28.4 Calendar 日历
/* * Calendar:日历,提供了一些操作年月日时的方法 * 获取 * 修改 * 添加 */ public class CalendarDemo { public static void mai ...
- JS入门系列(1)-原型-函数原型
实例1: 首先定义一个Persion类或者说是函数 var p1 = Persion();:表示,作为普通函数调用 var p2 = new Persion();:表示,作为构造器调用 创建函数之后, ...
- 四、华为VRP平台介绍和常用配置
一.华为VRP平台 华为现用的平台是VRP(Versatile Routing Platform)是华为公司数据通信产品的通用操作系统平台. 包含华为产品中的路由.交换.安全.无线等等 二.华为设备管 ...
- canal使用记录
canal是阿里巴巴的来源项目.我们可以通过配置binlog实现数据库监控,得到数据库表或者数据的更新信息.参考我的文档前先去官网看下,可能已经支持更高版本的MySQL了 1. 查看官方开源项目 ht ...
- ${param.pageNo}是什么意思?
1.${param.id}与request.getParameter("id"):功能相同2.param.id获取输入的参数id,也可理解为的是form或者div表单里的ID. r ...