Flink分布式运行时环境

一、Tasks and Operator Chains(任务与运算链)

在分布式执行时,Flink会将多个运算子任务链接到分布式计算任务中。每个任务都由一个线程执行。将运算符链接成任务是一个有用的优化:它减少了线程间切换和缓冲的开销,并增加了整体吞吐量,同时减少了延迟。链接行为可以在API中配置。

下图中的示例数据流由五个子任务执行,因此具有五个并行线程。
tasks_chains

二、Job Managers, Task Managers, Clients(作业管理器,任务管理器与客户端)

Flink运行时由如下两种进程构成:

  • JobManagers (也被叫做masters)用来协调分布式系统的的执行。主要功能是调度任务, 调整检查点, 协调失败恢复过程等。
    一个Flink环境中至少有一个Job Manager,一个高可用的系统在启动时会有多个JobManager,其中一个Job Manager一直是leader,其余的都随时待命,相当于主从机制。

  • TaskManagers (也被叫做workers)用来在一条数据流图中执行任务(确切得说这些tasks其实就是subtasks,即计算子任务), 并用于数据流的缓冲和数据交换。
    一个系统中至少要有一个TaskManager。

JobManagers和TaskManagers可以在如下几种方式下启动:直接在单机上启动, 在容器上启动, 或者通过YARN、Mesos这样的资源框架管理。TaskManagers主动上连到JobManagers, 报告自身是否可用,以便JobManagers分配任务给它们。

client不属于运行时环境的一个组成部分, 但它用于准备并将数据流图发送给JobManager。发送完数据流图后,client可以断开连接,或者保持连接用来接收程序执行结果。client可以用Java或者Scala的形式执行,也可以用命令行(./bin/flink run…)来执行。

processes

三、Task Slots and Resources(任务槽和资源)

每个worker(TaskManager)都是一个JVM进程,每个子任务都是运行在独立的线程中。为了控制一个worker接收任务的数量,一个任务会分配至少一个任务槽。

每一个任务槽都代表了一个TaskManager中特定的资源池子集。比如 TaskManager有三个任务槽,每个任务槽都有该TaskManager1/3的管理内存。将资源分槽意味着每一个计算子任务都有指定容量的内存资源,从而不会和其他子任务发生竞争。注意,这里没有对CPU隔离;任务槽只会隔离对应任务的内存。

用户通过调整任务槽的数量,可以自定义每个任务的计算子任务的数量。每个TaskManager只有一个任务槽的话,说明每个任务组都跑在一个独立的JVM上(如果Flink启动在一个独立的容器中)。有多个任务槽说明了有多个计算子任务在共享同一个JVM。在同一个JVM下的任务共享TCP连接(multiplexing:通过多路复用的方式)和心跳信息。任务之间也会共享数据集和数据结构,从而减少每个任务的开销。

tasks_slots

一般来说,即使计算子任务属于不同的任务,只要它们属于同一个job(作业),Flink都允许子任务共享任务槽。结果就是有可能每个槽都有完整的作业流水的场景。允许任务槽共享有以下两大好处:

  • 一个Flink集群需要在作业中确保任务槽数量和程序并发量完全一致,而并不需要计算程序中任务(每个任务的并发量也许都不相同)的具体数量。

  • 我们非常容易就可以提高资源利用率。如果没有任务槽共享机制,非密集型的source/map()子任务就会和密集型的window子任务一样阻塞大量资源。如果有这个机制的话,如果在程序的并发量从2提高到6的情况下,就可以让密集型的子任务完全分散到任务管理器中,从而可以显著得提高槽的资源利用率。

slot_sharing

Flink API中包含一个资源组机制,可以避免不合理的任务槽。

按照以往的经验来看,默认的任务槽数量应设置成CPU核心的数量。如果使用超线程技术,每个槽中甚至可以调度两个硬件线程。

四、State Backends(后端存储)

通过键值对索引的数据结构保存在选定的后端存储中。有的后端存储使用内存中的哈希表来存储数据,另外的后端存储会使用RocksDB来存储键值对。除了定义保存状态的数据结构外,后端存储还实现了获取键值对的特定时间点快照的功能,该功能可以将快照保存为检查点的一部分。

checkpoints

五、Savepoints(保存点)

使用Data Stream API的程序可以从保存点恢复过来。保存点可以在不丢失状态的情况下更新程序和Flink集群。

保存点是一种手动触发的检查点,获取程序快照并将其写入后端存储中。因此保存点依赖于常规检查点的机制。在程序执行期间,会定期得在worker节点生成快照和检查点。只有最新一个有效的检查点是对Flink修复机制有效的,一旦有新的检查点生成了,那些旧的检查点就可以被安全移除了。

保存点和定期检查点在大部分情况下很像,除了保存点是用户手动触发的,当新的检查点生成时,老的检查点不会自动到期失效。保存点可以通过命令行生成,也可以在调用 REST API 取消作业时产生。