4.1 Flink运行时的组件

image.png

每个组件都是一种JVM进程。

4.1.1 作业管理器(JobManager)

  • 控制一个应用程序执行的主进程。也就是说,每个应用程序都会被一个不同的JobManager所控制执行。
  • JobManager会先接收到要执行的应用程序,这个应用程序包括:
    • 作业图(JobGraph)
    • 逻辑数据流图(logical dataflow graph)
    • 打包了所有的类、库和其他资源的jar包。
  • JobManager会把JobGraph转换为一个物理层面的数据流图,这个图被叫做“执行图(Execution Graph)”,包含了所有可以并行执行的任务。
  • JobManager会向资源管理器(ResourceManager)请求执行任务必要的资源,也就是任务管理器(TaskManager)上的插槽(Slot)。一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的TaskManager上。而在运行过程中,JobManager会负责所有需要中央协调的操作,比如说检查点(Checkpoints)的协调。

    4.1.2 任务管理器(TaskManager)

  • Flink中的工作进程。通常Flink中会有多个TaskManager运行,每一个TaskManager都包含了一定数量的插槽(slots)。插槽的数量限制了TaskManager能够执行的任务数量。

  • 启动之后,TaskManager会向资源管理器注册它的插槽;收到资源管理器的指令后,TaskManager就会将一个或者多个插槽提供给JobManager调用。JobManager就可以向插槽分配任务(tasks)来执行了。
  • 在执行过程中,一个TaskManager可以跟其他运行同一应用程序的TaskManager交换数据。

    4.1.3 资源管理器(ResourceManager)

  • 主要负责管理任务管理器(TaskManager)的插槽(slot),TaskManager的插槽是Flink中定义的处理资源最小单元。

  • Flink为不同的环境和资源管理工具提供了不同资源管理器,比如YARN、Mesos、K8S,以及standalone部署。
  • 当Job Manager申请插槽资源时,Resource Manager会将有空闲插槽的Task Manager分配给Job Manager。如果Resource Manager没有足够的插槽来满足Job Manager的请求,它还可以向资源提供平台发起会话,以提供启动TaskManager进程的容器。

    4.1.4 分发器(Dispatcher)

  • 可以跨作业运行,它为应用提交提供了REST接口。

  • 当一个应用被提交执行时,分发器就会启动并将应用移交给一个JobManager。
  • Dispatcher也会启动一个Web UI,用来方便地展示和监控作业执行信息。
  • Dispatcher在架构中可能并不是必需的,这取决于应用运行的方式。

4.2 任务提交流程

image.png
flink_作业执行流程 (3).png

4.2.1 基于YARN的任务提交流程

Per-Job-Cluster模式

image.png


4.3 任务调度原理

image.png

4.3.1 思考

  • 怎样实现并行计算?
    • 答:为一个operator设置大于1的并行度,从而形成多个任务,并分配到不同的slot(线程)上并行执行。
  • 并行的任务,需要占用多少slot?
    • 答:通常情况下,占用slot数量等于各步骤operator中最大的并行度,与有多少个步骤无关。
  • 一个流处理橙心,到底包含多少个任务(operator到任务的拆分逻辑)?

    4.3.2 并行度(Parallelism)

    image.png

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

    4.3.3 TaskManager和Slots

    image.png

  • Flink中每一个TaskManager都是一个JVM进程,它可能会在独立的线程上执行一个或多个子任务。

  • 为了控制一个TaskManager能接收多少个Task,TaskManager通过Task Slot来进行控制(一个TaskManager至少有一个Slot)。

image.png

  • 默认情况下,Flink允许子任务共享slot,即使它们是不同任务的子任务(所有子任务默认同属default组)。这样的结果是,一个slot可以保存作业的整个管道
    • 在不分区情况下,同一个slot中数据交换效率高,执行性能高。
    • 一个slot保存完整的管道,有利于资源分配和高可用。如果一个slot挂了,则只影响并行度,不影响作业完成,也不会造成资源浪费。
    • 一个slot保存完整的管道,有利于平衡“IO密集”和“CPU密集”型子任务对CPU的使用,避免造成“IO密集”型子任务独占Slot的情况。
  • 在代码中,可以对各个算子指定slotSharingGroup,从而明确指定哪些算子的并行子任务应该分到一个组。不同组的子任务一定会分配到不同slot中。
  • Task Slot是静态的概念,是指TaskManager具有的并发执行能力。通常slot数量设置为TaskManager所在机器的CPU核心数。

    4.3.4 并行子任务的分配

    image.png

    4.3.5 程序与数据流(DataFlow)

    image.png

  • 所有Flink程序都是由三部分组成:

    • Source:负责从外部系统读取数据。
    • Transformation:利用各种算子对数据进行处理加工。
    • Sink:负责输出数据到外部系统。
  • 在运行时,Flink上运行的程序会被映射成“逻辑数据流(dataflows)”,它包含了以上三部分。
  • 没有给dataflow以一个或多个sources开始,以一个或多个sinks结束。dataflow类似于有向无环图(DAG)。
  • 在大部分情况下,程序中的转换运算(transformations)跟dataflow中的算子(operator)是一一对应的关系。

    4.3.6 执行图(Execution Graph)

  • Flink中的执行图可以分成四层:StreamGraph -> JobGraph -> ExecutionGraph -> 物理执行图

    • StreamGraph:根据用户通过Stream API编写的代码生成的最初的图。用来表示程序的拓扑结构。
    • JobGraph:StreamGraph经过优化胡生成了JobGraph。是提交给JobManager的数据结构。主要优化为,将多个符合条件的节点chain在一起作为一个节点
    • ExecutionGraph:JobManager根据JobGraph生成的ExecutionGraph。ExecutionGraph是JobGraph的并行化版本,是调度层最核心的数据结构。
    • 物理执行图:JobManager根据ExecutionGraph对Job进行调度后,在各个TaskManager上部署Task后形成的“图”,并不是一个具体的数据解雇。

image.png

4.3.7 数据传输形式

  • 一个程序中,不同的算子可能具有不同的并行度。
  • 算子之间传输数据的形式可以时one-to-one(forwarding)的模式,也可以是redistributing的模式,具体是哪一种模式,取决于算子的种类。
    • one-to-one:stream维护着分区以及元素的顺序(比如surce和map之间)。这意味着map算子的子任务看到的元素的个数以及顺序跟source算子的子任务生产的元素的个数、顺序相同。map、filter、flatMap等算子都是one-to-one的对应关系。
    • redistributing:stream的分区会发生改变。每一个算子的子任务依据所选择的transformation发送数据到不同的目标任务。例如,keyBy基于hashCode重分区、而broadcast和rebalance会依据各自规则重新分区,这些算子都会引起redistribute过程,而redistribute过程就类似于Spark中的shuffle过程。

      注意:

      • keyBy操作并不是个算子(图中不会作为黄色圆圈展示),而只是将前后两个算子的数据传输形式改变为hash。

4.3.8 任务链

  • Flink采用了一种称为任务链的优化技术,可以在特定条件下减少本地通信的开销。为了满足任务链的要求,必须将两个或多个算子设为相同的并行度,并通过本地转发(local forward)的方式进行连接。
  • 前后两个算子形成任务链的条件:
    • 同属一个slotSharingGroup
    • 并行度相同
    • 是one-to-one(forward)操作(数据从前一个算子流向后一个算子时不会发生重分区)。
    • 算子未设置disableChaining、startNewchain

image.png