flink 数据流图、并行度、算子链、JobGraph与ExecutionGraph、任务和任务槽


1. 数据流图(Dataflow Graph)

  所有的 Flink 程序都可以归纳为由三部分构成:Source、Transformation 和 Sink

Source 表示“源算子”,负责读取数据源
Transformation 表示“转换算子”,利用各种算子进行处理加工
Sink 表示“下沉算子”,负责数据的输出

在这里插入图片描述
  在运行时,Flink 程序会被映射成所有算子按照逻辑顺序连接在一起的一张图,这被称为逻辑数据流(logical dataflow),或者叫数据流图(dataflow graph)
  数据流图类似于有向无环图(DAG),每一条数据流(dataflow)以一个或多个 source 算子开始,以一个或多个 sink 算子结束。
  除了 Source 读取数据和 Sink 输出数据,一个中间的转换算子(Transformation Operator)必须是一个转换处理的操作;而在代码中有一些方法调用,数据是没有完成转换的。可能只是对属性做了一个设置,也可能定义的是数据的传递方式而非转换,又或者是需要几个方法合在一起才能表达一个完整的转换操作

如:
keyBy方法 ,就只是一个数据分区操作,而并不是一个算子。在代码中可以看到调用其他转换操作之后返回的数据类型是 SingleOutputStreamOperator,说明这是一个算子操作;而 keyBy 之后返回的数据类型是 KeyedStream

在这里插入图片描述


2. 并行度(Parallelism)

2.1 并行子任务和并行度

  把一个算子操作,“复制”多份到多个节点,数据来了之后就可以到其中任意一个执行。这样一来,一个算子任务就被拆分成了多个并行的“子任务”(subtasks),再将它们分发到不同节点,就真正实现了并行计算
  在 Flink 执行过程中,每一个算子(operator)可以包含一个或多个子任务(operator subtask),这些子任务在不同的线程、不同的物理机或不同的容器中完全独立地执行。
在这里插入图片描述
  一个特定算子的子任务(subtask)的个数被称之为其并行度(parallelism)。包含并行子任务的数据流,就是并行数据流,它需要多个分区(stream partition)来分配并行任务。一般情况下,一个流程序的并行度,可以认为就是其所有算子中最大的并行度。一个程序中,不同的算子可能具有不同的并行度。

2.2并行度的设置优先级

(1)对于一个算子,首先看在代码中是否单独指定了它的并行度,这个特定的设置优先级最高,会覆盖后面所有的设置
(2)如果没有单独设置,那么采用当前代码中执行环境全局设置的并行度
(3)如果代码中完全没有设置,那么采用提交时-p 参数指定的并行度
(4)如果提交时也未指定-p 参数,那么采用集群配置文件中的默认并行度

注意:算子的并行度有时会受到自身具体实现的影响。如读取 socket 文本流的算子 socketTextStream,本身就是非并行的 Source 算子,所以无论怎么设置,它在运行时的并行度都是 1,对应在数据流图上就只有一个并行子任务

3. 算子链(Operator Chain)

  Web UI 上的图与代码中的算子并非一定一一对应
在这里插入图片描述
算子间的数据传输存在2中模式:

(1)一对一(One-to-one,forwarding)
这种模式下,数据流维护着分区以及元素的顺序。如 source 和 map 算子,source算子读取数据之后,直接发送给 map 算子做处理,它们之间不需要重新分区,也不需要调整数据的顺序。这就意味着 map 算子的子任务,看到的元素个数和顺序跟 source 算子的子任务产生的完全一样,保证着“一对一”的关系。map、filter、flatMap 等算子都是这种 one-to-one的对应关系。
这种关系类似于 Spark 中的窄依赖

(2)重分区(Redistributing)
在这种模式下,数据流的分区会发生改变。每一个算子的子任务,会根据数据传输的策略,把数据发送到不同的下游目标任务。如keyBy()是分组操作,本质上基于键(key)的哈希值(hashCode)进行了重分区;而当并行度改变时,数据传输方式是再平衡(rebalance),会把数据均匀地向下游子任务分发出去。这些传输方式都会引起重分区(redistribute)的过程,这一过程类似于 Spark 中的 shuffle。
这种算子间的关系类似于 Spark 中的宽依赖

合并算子链:
  在 Flink 中,并行度相同的一对一(one to one)算子操作,可以直接链接在一起形成一个
任务(task),每个 task会被一个线程执行。这样的技术被称为“算子链”(Operator Chain)。算子链接成 task 是非常有效的优化:可以减少线程之间的切换和基于缓存区的数据交换,在减少时延的同时提升吞吐量

禁止合并或者自行定义算子链:

// 禁用算子链
.map(word -> Tuple2.of(word, 1L)).disableChaining();
// 从当前算子开始新链
.map(word -> Tuple2.of(word, 1L)).startNewChain()

4. 作业图(JobGraph)与执行图(ExecutionGraph)

  执行一个流处理程序,Flink 需要将逻辑流图进行解析,转换为物理数据流图

逻辑流图(StreamGraph)→ 作业图(JobGraph)→ 执行图(ExecutionGraph)→ 物理图(Physical Graph)

4.1 逻辑流图(StreamGraph)

  根据用户通过 DataStream API 编写的代码生成的最初的 DAG 图,用来表示程序的拓扑结构。这一步一般在客户端完成。

4.2 作业图(JobGraph)

  StreamGraph 经过优化后生成的就是作业图(JobGraph),这是提交给 JobManager 的数据结构,确定了当前作业中所有任务的划分。主要的优化为: 将多个符合条件的节点链接在一起合并成一个任务节点,形成算子链,这样可以减少数据交换的消耗。JobGraph 一般也是在客户端生成的,在作业提交时传递给 JobMaster。

4.3 执行图(ExecutionGraph)

  JobMaster 收到 JobGraph 后,会根据它来生成执行图(ExecutionGraph)。ExecutionGraph是 JobGraph 的并行化版本,是调度层最核心的数据结构。

4.4 物理图(Physical Graph)

  JobMaster 生成执行图后, 会将它分发给 TaskManager;各个 TaskManager 会根据执行图部署任务,最终的物理执行过程也会形成一张“图”,一般就叫作物理图(Physical Graph)。这只是具体执行层面的图,并不是一个具体的数据结构。


5. 任务(Tasks)和任务槽(Task Slots)

5.1 任务槽(Task Slots)

  Flink 中每一个 worker(TaskManager)都是一个 JVM 进程,它可以启动多个独立的线程,来并行执行多个子任务(subtask)。每个任务槽(task slot)其实表示了 TaskManager 拥有计算资源的一个固定大小的子集
在这里插入图片描述

5.2 任务槽数量的设置

taskmanager.numberOfTaskSlots: 8

  通过调整 slot 的数量,我可以控制子任务之间的隔离级别
  具体来说,如果一个 TaskManager 只有一个 slot,那将意味着每个任务都会运行在独立的JVM 中;而一个 TaskManager 设置多个slot 则意味着多个子任务可以共享同一个 JVM。它们的区别在于:前者任务之间完全独立运行,隔离级别更高、彼此间的影响可以降到最小;而后者在同一个 JVM 进程中运行的任务,将共享 TCP 连接和心跳消息,也可能共享数据集和数据结构,这就减少了每个任务的运行开销,在降低隔离级别的同时提升了性能。
  注意,slot 目前仅仅用来隔离内存,不会涉及 CPU 的隔离。在具体应用时,可以将 slot 数量配置为机器的 CPU 核心数,尽量避免不同任务之间对 CPU 的竞争。这也是开发环境默认并行度设为机器 CPU 数量的原因。

5.3 任务对任务槽的共享

在这里插入图片描述

  在flink执行作业时,每个任务节点的并行子任务一字排开,占据不同的 slot;而不同的任务节点的子任务可以共享 slot。假设,一个 slot 中,可以将程序处理的所有任务都放在这里执行,把它叫作保存了整个作业的运行管道(pipeline)
  Flink 默认是允许 slot 共享的,如果希望某个算子对应的任务完全独占一个 slot,或者只有某一部分算子共享 slot,我可以通过设置“slot 共享组”(SlotSharingGroup)手动指定:

.map(word -> Tuple2.of(word, 1L)).slotSharingGroup("1");

5.4 任务槽和并行度的关系

  task slot 是 静 态 的 概 念 , 是 指 TaskManager 具 有 的 并 发 执 行 能 力 , 可 以 通 过 参 数taskmanager.numberOfTaskSlots 进行配置;而并行度(parallelism)是动态概念,是TaskManager 运行程序时实际使用的并发能力,可以通过参数 parallelism.default 进行配置

  并行度如果小于等于集群中可用 slot 的总数,程序是可以正常执行的;而如果并行度大于可用 slot 总数,导致超出了并行能力上限
  因此把所有的 slot 运用起来,作业并行度效率最高


  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

但行益事莫问前程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值