flink并行度知识点

Flink的基本构建

  • 流(Stream):流是对当前数据流向的记录(流也可能是永无止境的) 。
  • 转换(Transform):转换是将一个或多个流作为输入,根据需要求转换成我们要的格式的流的过程。
  • 当程序执行时,Flink程序会将数据流进行映射、转换运算成我们要的格式的流。每个数据流都以一个或多个源(Source)开始,并以一个或多个接收器(Sink)结束,数据流类似于任意有向无环图(DAG)

在这里插入图片描述

Flink 中的程序本质上是并行的。在执行期间,每一个算子(Transformation)都有一个或多个算子subTask(Operator SubTask),每个算子的 subTask 之间都是彼此独立,并在不同的线程中执行,并且可能在不同的机器或容器上执行。Operator subTask 的数量指的就是算子的并行度。同一程序的不同算子也可能具有不同的并行度(因为可以通过 setParallelism() 方法来修改并行度)

subtask、task、operator chains、slot概念

  • Task:Task 是一个阶段多个功能相同 subTask 的集合,类似于 Spark 中的 TaskSet。
  • subTask:subTask 是 Flink 中任务最小执行单元,是一个 Java 类的实例,这个 Java 类中有属性和方法,完成具体的计算逻辑。
  • Operator Chains:没有 shuffle 的多个算子合并在一个 subTask 中,就形成了 Operator Chains,类似于 Spark 中的 Pipeline。
  • Slot:Flink 中计算资源进行隔离的单元,一个 Slot 中可以运行多个 subTask,但是这些 subTask 必须是来自同一个 application 的不同阶段的 subTask。

同一个application,多个 task的 subTask,可以运行在同一个slot资源槽中;但是同一个 task 中的多个 sub-task不能运行在一个 slot 资源槽中,他们会被分散到不同的slot中。这就限制了我们的任何一个算子的并行度不能设置的超过集群总slot的数量,否则集群不能正常的运行。

为何slot共享

任务槽是Flink计算资源的基本单位,每个任务槽可以在同一时间执行一个Task,而TaskManager可以拥有一个或者多个任务槽。

Flink允许任务槽共享,即来自同一个Job的不同Task的Sub-Task(理解为Task的子集就行)进入同一个槽位。

任务槽共享有两点好处:

  • Flink 集群所需的 slot 与作业中使用的最高并行度 parallelism 恰好一样多;无需计算一个程序总共包含多少个 job (具有不同的并行度);作业需要的任务槽数量必须等于Job中最大的并行度
  • 更好的资源利用率。如果没有 slot sharing,则非密集型 source / map()子任务将阻塞与资源密集型窗口子任务一样多的资源。而通过 slot sharing,可以充分利用插槽资源,同时确保沉重的 subtask 在 TaskManager 之间公平分配。

TaskManager数量

所以,可以得出Flink on YARN时,TaskManager数量 = max(parallelism) / yarnslots(向上取整)

例如,一个最大并行度为10,每个TaskManager有两个任务槽的作业,就会启动5个TaskManager。

何时划分Task 

  • 并行度发生变化时
  • keyBy() /window()/apply() 等发生 Rebalance 重新分配
  • 调用 startNewChain() 方法,开启一个新的算子链
  • 调用 diableChaining()方法,告诉当前算子操作不使用算子链操作

针对内存密集型、CPU密集型,使用 startNewChins()、disableChaining()方法,可以将当前算子单独放到一个 Task 中,使其独享当前Task的所有资源,以此来提升计算效率。

计算Task数量

flink会根据sub-task的传输方式来划分这个application中有多少个task以及sub-task。flink会根据sub-task是否会发生Operator Chain来划分task。

以下图为例

  • source、map合成的task的并行度为6
  • keyby 、window、apply合成的task的并行度为6
  • sink的并行度为1
  • 总共有13个task

在这里插入图片描述

Task slot和Parallelism

非资源密集型的算子:source map sink

资源密集型的算子:aggregate reduce sum window

非资源密集型的算子和资源密集型的算子可以分配到同一个slot中 ,这样所有的slot之间任务就会平等,不会存在一直空闲一直高负载。

flink 也能做到把非资源密集型和资源密集型的算子分到不同的slot中 这里需要设置共享组,非资源 密集型 的算子在一个共享组,资源密集 型的算子在一个共享组,这样这两种算子就不会共享的使用slot。默认情况下算有算子都属于同一个共享组,共享所有slot。

  • 默认情况下,Flink 允许子任务共享 slot,即使它们是不同任务的子任务但是可以分配到同一个slot上。 这样的结果是,一个 slot 可以保存多个作业的整个管道
  • Task Slot 是静态的概念,表示 TaskManager 具有多少并发执行能力
  • Parallelism是动态的概念,表示程序运行时实际使用时的并发能力
  • 设置的 parallelism 不能高于 slot 数量,不然将会出现计算资源不够用的情况,程序报错

并行度(Parallelism)

一个特定算子的 子任务(subtask)的个数被称之为其并行度(parallelism)。一般情况下,一个 stream 的并行度,可以认为就是其所有算子中最大的并行度。

flink并行分两个方面

  • 数据并行:source 并行拉数据 map 并行处理数据
  • 计算并行:source 在拉新数据,map 在处理source 之前拉的数据,两个 job 的并行执行

合理设置并行度,对operator chain带来的优化:

  • 减少本地通信的开销
  • 减少序列化和反序列化

Flink程序中设定并行度有4种级别,实际执行时优先级从高到低分别为:算子级别、执行环境(ExecutionEnvironment)级别、客户端(命令行)级别、配置文件(flink-conf.yaml)级别。

  • 算子级别

dataStream.flatMap(new SomeFlatMapFunction()).setParallelism(4);

  • 执行环境级别

streamExecutionEnvironment.setParallelism(4);

  • 命令行级别

bin/flink -run --parallelism 4 example-0.1.jar

任何一个算子的并行度不能设置的超过集群总slot的数量,否则集群不能正常的运行。

  • flink-conf.yaml级别

parallelism.default: 4

Stream、Operator、Subtask的关系

  • 一个Stream可以被分成多个Stream分区
  • 一个Operator可以被分成多个Operator Subtask
  • 每一个Operator Subtask是在不同的线程中独立执行的
  • 一个Operator的并行度等于Operator Subtask的个数
  • 一个Stream的并行度总是等于生成它的Operator的并行度

Stream分区数 = Stream并行度 = 生成Stream的Operator的并行度 = Operator Subtask的个数

operator之间传递模式

  • one-to-one 模式:两个operator用此模式传递的时候,会保持数据的分区数和数据的排序
  • Redistributing 模式:这种模式会改变数据的分区数;每个一个operator subtask会根据选择transformation把数据发送到不同的目标subtasks,比如keyBy()会通过hashcode重新分区,broadcast()和rebalance()方法会随机重新分区

operator chain

operator chain的条件

  • 算子属于one-to-one
  • 算子具有相同并行度(具有相同的分区数)
  • 两个节点间数据分区方式是 forward

在分布式计算中,Flink 将算子(operator)的 subtask 链接(chain)成 task。每个 task 由一个线程执行。把算子链接成 tasks,也就是 Operator Chain, 能够减少线程间切换和缓冲的开销,在降低延迟的同时提高了整体吞吐量。

Flink  Slot 插槽和 Parallelism 并行度

上图中,source 和 map 这两个 operator 进行了合并,在第二个视图中,每个虚框表示一个子任务,最终使用了 5 个并行的线程来执行。

如果没有开启 Operator Chain,那么使用的线程数将会增加到 7,线程数增加后,会增加开销。

 

数据重分区(Redistributing)

默认情况下,数据是自动分配到多个实例上的。有的时候我们需要手动对数据在多个实例上进行分配,以避免数据倾斜,避免部分实例负载过重,从而导致整个作业的计算时间过长或者内存不足等问题。

  • shuffle:shuffle基于正态分布,将数据随机分配到下游各算子实例上。
  • rebalance:rebalance使用Round-ribon思想将数据均匀分配到各实例上。Round-ribon是负载均衡领域经常使用的均匀分配的方法,上游的数据会轮询式地分配到下游的所有的实例上
  • rescale:rescale与rebalance很像,也是将数据均匀分布到各下游各实例上,但它的传输开销更小,因为rescale并不是将每个数据轮询地发送给下游每个实例,而是就近发送给下游实例。
  • broadcast:在Flink里,数据会被复制并广播发送给下游的所有实例上。
  • global:global会所有数据发送给下游算子的第一个实例上,使用这个算子时要小心,以免造成严重的性能问题。
  • partitionCustom:我们也可以使用partitionCustom来自定义数据重分布逻辑。
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值