深入理解Flink:实时大数据处理实践
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.4 运行时

2.4.1 运行时结构

1.Task线程

线程是程序运行时的最小单元,是进程中的一个实体,是被系统独立调度的基本单位,同属一个进程的所有线程共享进程所拥有的全部资源。

Flink的每个Operator称为一个任务(task),Operator的每个实例称为子任务,每个任务(包括子任务)在一个JVM线程中执行。可以将多个子任务链接(chain)成一个任务,在一个线程中执行,这会降低线程上下文切换产生的开销,减小缓存容量,提高系统吞吐量的同时降低延迟。此外,这种链接机制是可配置的,这增强了数据处理应用程序的灵活性。

机制与策略:理论指导引擎架构实现,但是实现通常考虑得更多。架构通常要权衡复杂度和灵活性,即引擎在简化复杂度的情况下提供什么机制(提供什么能力)、应用程序将会获得更丰富的实现策略(如何使用这些能力)。

在Programm 2.1中,Source[1]和map()[1]、Source[2]和map()[2]分别链接成一个任务,这种编排是因为Source和map的两个实例之间采用直连模式,它们之间的数据传输可以通过缓存而不是网络通信,正是这种针对性的优化提升了Flink的执行效率。整个应用程序由5个线程构成,如图2-8所示。

图2-8 Programm 2.1的执行线程

从图 2-8 中可见,应用程序由 Operator 的线程组成,也被称为作业(Job)。其中同一作业的一个数据传输通路也被称为一个管道,它用于连接多个命令,将一个命令的执行结果输出给下一个命令。如Source[1]、map()[1]、keyBy()/window()/apply()[1]和Sink[1]。

管道这个概念最早出现在UNIX操作系统中,下面是UNIX(类UNIX系统)的一个例子:

上面的命令将当前登录系统用户的信息转换为大写后保存至/tmp/who.out文件中,输出结果如下:

UNIX系统借用管道的模式将多个独立的命令内聚在一起,以链的方式将它们串接成处理第一个命令(who)输出文本信息的工作流,以降低软件模块(如本例中的命令)之间的耦合。

这是一种重要的软件设计模式,实现了组件之间的“高内聚,低耦合”,降低了模块间协同编程的难度。

这种设计模式在数据处理中有着广泛应用,如何将一系列可伸缩的并行算子编排起来解决目标计算任务,是数据处理引擎的主要任务之一。

2.Manager进程

Flink由两类运行时JVM进程(process)管理分布式集群的计算资源。

(1)JobManager进程负责分布式任务管理,如任务调度、检查点、故障恢复等。在高可用(HA,High-Availability)分布式部署时,系统中可以有多个JobManager,即一个 leader 加多个 standby。JobManager 是 Flink 主从架构中的master。

(2)TaskManager 进程负责执行任务线程(Programm 2.1 物理部署形式中的Subtask),以及缓存和传输stream。TaskManager是Flink主从架构中的worker。

此外,作为作业的发起者,客户端(client)向 JobManager 提交作业,但客户端并不是Flink运行时的一部分,图2-9描述了这三者的关系。

图2-9 client、JobManager、TaskManager之间的关系

3.线程共享Slot

为了控制执行的任务数量,TaskManager 将计算资源划分为多个Slot,每个Slot独享给其分配的计算资源(如内存),这种静态的资源管理方式有利于任务间资源隔离。

TaskManager可以配置成单Slot模式,这样这个worker上运行的任务就独占了整个JVM进程;同一个JVM进程上的多个任务可以共享TCP连接、心跳和数据。

Flink不允许属于不同作业的任务共享同一个Slot,但允许属于同一个作业的不同任务共享同一个 Slot,因此同一个作业的所有任务可共享同一个 Slot,如图2-10所示。

图2-10 TaskManager的Task Slot

2.4.2 任务调度

1.调度策略

以下代码片段对应一个包括Source、map和reduce的Pipeline:

其中,Source和map的并行度设置为4(setParallelism(4)),reduce的并行度设置为3,Source和map实例间采用直连模式,每个map和所有reduce均有连接。这个Pipeline被调度在两个TaskManager上执行,其中每个TaskManager有3个Slot。

出于提升执行效率的考虑,Flink 的任务调度系统会并发地执行流处理Pipeline中的任务,批处理通常也是如此。应用这种调度策略,本例的调度结果如图2-11所示。

图2-11 Flink任务的调度结果

Flink通过CoLocationGroup和SlotSharingGroup管理任务的调度约束关系,CoLocationGroup 规定哪些任务必须被调度在同一个 Slot 上运行,而SlotSharingGroup则定义哪些任务可以被调度在同一个Slot上运行,Flink的任务调度系统可以根据集群资源使用情况最优化地调度执行作业任务。

2.作业控制

JobManager 将计算图的逻辑形式(JobGraph)编译成物理部署形式(ExecutionGraph):

(1)JobGraph由Operator和传输通道的数据缓存(Intermediate Data Set)组成。其中,Operator是计算图中的顶点(JobVertex),并行度控制其实例数量,处理函数(ProcessFunction)定义转换函数。(2)ExecutionGraph由ExecutionVertex和Intermediate Result的多个分区组成。每个作业的JobVertex都对应一个ExecutionJobVertex,一个ExecutionJobVertex对应多个并行ExecutionVertex实例;数据缓存也被拆分成多个分区,即Intermediate Result Partition。

例如,一个 JobGraph 有 4 个顶点,分别记为 JobVertex(A)、JobVertex(B)、JobVertex(C)和JobVertex(D);每个顶点的输出都会有Intermediate Data Set。在对应的ExecutionGraph中,每个JobVertex对应一个ExecutionJobVertex,包括每个JobVertex 的所有并行实例,如 JobVertex(A)对应 ExecutionVertex A(0/2)和ExecutionVertex A(1/2)。整个作业控制的数据结构如图2-12所示。

图2-12 作业控制的数据结构

Flink通过状态机管理ExecutionGraph的作业执行进度。在被创建时,作业的状态为Created,然后被调度执行,作业的状态流转至Running,在所有JobVertex正常执行完处理任务后,作业结束,即处于 Finished 状态。此外,作业在执行过程中可能会出错,这时状态会流转至Failing、Restarting、Canceled或Failed;作业也可能被Client取消,这时状态可能会流转至Cancelling、Suspended或Canceled。作业的状态机转换过程,如图2-13所示。

图2-13 作业的状态机转换过程

2.4.3 物理执行计划

我们可以通过Web控制台观察作业的物理执行计划。以Socket Window Word Count为例,单击Web Flink Dashboard的“Add New+”按钮来添加任务,如图2-14所示。

图2-14 添加任务

选择打包好的SocketWindowWordCount程序,并输入参数(--port 9000),单击“Show Plan”按钮,则可获取该程序的物理执行计划,如图2-15所示。

图2-15 SocketWindowWordCount程序的物理执行计划