目录
[一、Apache Flink架构组件栈](#一、Apache Flink架构组件栈)
[1.1 概述](#1.1 概述)
[1.2 架构图](#1.2 架构图)
[1.3 架构分层组件说明](#1.3 架构分层组件说明)
[1.3.1 物理部署层](#1.3.1 物理部署层)
[1.3.2 Runtime 核心层](#1.3.2 Runtime 核心层)
[1.3.3 API & Libraries层](#1.3.3 API & Libraries层)
[2.1 概述](#2.1 概述)
[2.2 架构图](#2.2 架构图)
[2.3 架构角色和组件](#2.3 架构角色和组件)
[2.3.1 Flink Clients客户端](#2.3.1 Flink Clients客户端)
[2.3.2 JobManager](#2.3.2 JobManager)
[2.3.2.1 ResourceManager](#2.3.2.1 ResourceManager)
[2.3.2.2 Dispatcher](#2.3.2.2 Dispatcher)
[2.3.2.3 JobMaster](#2.3.2.3 JobMaster)
[2.3.3 TaskManager](#2.3.3 TaskManager)
[2.3.3.1 Tasks 和算子链](#2.3.3.1 Tasks 和算子链)
[2.3.3.2 Task Slots 和资源](#2.3.3.2 Task Slots 和资源)
[三、Flink 三种提交作业模式对比](#三、Flink 三种提交作业模式对比)
[3.1 概述](#3.1 概述)
[3.2 Flink Session 集群](#3.2 Flink Session 集群)
[3.4 Flink Application 集群](#3.4 Flink Application 集群)
一、Apache Flink架构组件栈
1.1 概述
在Flink的整个软件架构体系中,同样遵循这分层的架构设计理念,在降低系统耦合度的同时,也为上层用户构建Flink应用提供了丰富且友好的接口。
1.2 架构图
上图是Flink基本组件栈,从上图可以看出整个Flink的架构体系可以分为三层,从下往上依次是物理部署层、Runtime 核心层、API&Libraries层。
1.3 架构分层组件说明
1.3.1 物理部署层
该层主要涉及Flink的部署模式,目前Flink支持多种部署模式:本地Local、集群(Standalone/Yarn)、Kubernetes,Flink能够通过该层支撑不同平台的部署,用户可以根据需要来选择对应的部署模式,目前在企业中使用最多的是基于Yarn进行部署,也就是Flink On Yarn。
1.3.2 Runtime 核心层
该层主要负责对上层不同接口提供基础服务,也是Flink分布式计算框架的核心实现层,支持分布式Stream作业的执行、JobGraph到ExecutionGraph的映射转换、任务调度等,将DataStream和DataSet转成统一可执行的Task Oparator,达到在流式引擎下同时处理批量计算和流式计算的目的。
1.3.3 API & Libraries层
作为分布式计算框架,Flink同时提供了支撑流计算和批计算接口,未来批计算接口会被弃用,在Flink1.15 版本中批计算接口已经标记为Legacy(已过时),后续版本建议使用Flink流计算接口,基于此接口之上抽象出不同应用类型的组件库,例如:FlinkML 机器学习库、FlinkCEP 复杂事件处理库、Flink Gelly 图处理库、SQL&Table 库。DataSet API 和DataStream API 两者都提供给用户丰富的数据处理高级API,例如:Map、FlatMap操作等,同时也提供了比较底层的Process Function API ,用户可以直接操作状态和时间等底层数据。
二、Flink运行时架构
2.1 概述
Flink整个系统主要由两个组件组成,分别为JobManager和TaskManager,Flink架构也遵循Master-Slave架构设计原则,JobManager为Master节点,TaskManager为Worker(Slave)节点。所有组件之间的通信都是借助于Akka Framework,包括任务的状态以及Checkpoint触发等信息。
2.2 架构图
2.3 架构角色和组件
2.3.1 Flink Clients客户端
Flink客户端负责将任务提交到集群,与JobManager构建Akka连接,然后将任务提交到JobManager,通过和JobManager之间进行交互获取任务执行状态。Flink客户端Clients不是Flink程序运行时的一部分,作用是向JobManager准备和发送dataflow,之后,客户端可以断开(detached mode)连接或者保持连接(attached mode)。客户端提交任务可以采用CLI方式或者通过使用Flink WebUI提交,也可以在应用程序中指定JobManager的RPC网络端口构建ExecutionEnvironment提交Flink应用。
2.3.2 JobManager
JobManager负责整个Flink集群任务的调度以及资源的管理,从客户端中获取提交的应用,然后根据集群中TaskManager上TaskSlot的使用情况,为提交的应用分配相应的TaskSlots资源并命令TaskManger启动从客户端中获取的应用。
JobManager相当于整个集群的Master节点,Flink HA 集群中可以有多个JobManager,但整个集群中有且仅有一个活跃的JobManager,其他的都是StandBy。
JobManager和TaskManager之间通过Actor System进行通信,获取任务执行的情况并通过Actor System将应用的任务执行情况发送给客户端。同时在任务执行过程中,Flink JobManager会触发Checkpoints操作,每个TaskManager节点收到Checkpoint触发指令后,完成Checkpoint操作,所有的Checkpoint协调过程都是在Flink JobManager中完成。
当任务完成后,Flink会将任务执行的信息反馈给客户端,并且释放掉TaskManager中的资源以供下一次提交任务使用。
JobManager由三个不同的组件组成:
2.3.2.1 ResourceManager
这里说的ResourceManager不是Yarn资源管理中的ResourceManager,而是Flink中的ResourceManager,其主要负责Flink集群资源分配、管理和回收。在Flink中这里说的资源主要是TaskManager节点上的Task Slot计算资源,Flink中每个提交的任务最终会转换成task,每个task需要发送到TaskManager 上的slot中执行(slot是资源调度最小的单位),Flink为不同的环境和资源提供者(例如:Yarn/Kubernetes和Standalone)实现了对应的ResourceManager,这些ResourceManager负责申请启动TaskManager获取Slot资源。
在Standalone集群中,集群启动会同时启动TaskManager,不支持提交任务时启动TaskManager(没有Per-Job任务提交模式),ResourceManager只能分配可用TaskManager的slots,而不支持自行启动新的TaskManager,而基于其他资源调度框架执行任务时,当ResourceManager管理对应的TaskManager没有足够的slot,会申请启动新的TaskManager进程。
2.3.2.2 Dispatcher
Dispatcher提供了一个REST接口,用来提交Flink应用程序执行,例如CLI客户端或Flink Web UI提交的任务最终都会发送至Dispatcher组件,由Dispatcher组件对JobGraph进行分发和执行,并为每个提交的作业启动一个新的 JobMaster,它还运行 Flink WebUI 用来提供作业执行信息。
2.3.2.3 JobMaster
JobMaster负责管理整个任务的生命周期,负责将Dispatcher提交上来的JobGraph转换成ExecutionGraph(执行图)结构,通过内部调度程序对ExecutionGraph执行图进行调度和执行,最终向TaskManager中提交和运行Task实例,同时监控各个Task的运行状况,直到整个作业中所有的Task都执行完毕。
JobManager和ResourceManager组件一样,JobManager组件本身也是RPC服务,具备通信能力,可以与ResourceManager进行RPC通信申请任务的计算资源,资源申请到位后,就会将对应Task任务发送到TaskManager上执行,当Flink Task任务执行完毕后,JobMaster服务会关闭,同时释放任务占用的计算资源。所以JobMaster与对应的Flink job是一一对应的。
2.3.3 TaskManager
TaskManager负责向整个集群提供Slot计算资源,同时管理了JobMaster提交的Task任务。TaskManager会提供JobManager从ResourceManager中申请和分配的Slot计算资源,JobMaster最终会根据分配到的Slot计算资源将Task提交到TaskManager上运行。另外,TaskManager还可缓存数据,TaskManager之间可以进行DataStream数据的交换。
一个Flink集群中至少有一个TaskManager,在TaskManager中资源调度的最小单位是 task slot ,一个TaskManger中的task Slot个数决定了当前TaskManger最高支持的并发task个数,一个task Slot中可以执行多个算子。
可以看出,Flink的任务运行其实是采用多线程的方式,这和MapReduce多JVM进程的方式有很大的区别Fink能够极大提高CPU使用效率,在多个任务和Task之间通过TaskSlot方式共享系统资源,每个TaskManager中通过管理多个TaskSlot资源池进行对资源进行有效管理。
2.3.3.1 Tasks 和算子链
对于分布式执行,Flink 将算子的 subtasks 链接成 tasks 。每个 task 由一个线程执行。将算子链接成 task 是个有用的优化:它减少线程间切换、缓冲的开销,并且减少延迟的同时增加整体吞吐量。
下图中样例数据流用 5 个 subtask 执行,因此有 5 个并行线程:
2.3.3.2 Task Slots 和资源
每个 worker(TaskManager)都是一个 JVM 进程,可以在单独的线程中执行一个或多个 subtask。为了控制一个 TaskManager 中接受多少个 task,就有了所谓的 task slots(至少一个)。
每个 task slot代表 TaskManager 中资源的固定子集。例如,具有 3 个 slot 的 TaskManager,会将其托管内存 1/3 用于每个 slot。分配资源意味着 subtask 不会与其他作业的 subtask 竞争托管内存,而是具有一定数量的保留托管内存。注意此处没有 CPU 隔离;当前 slot 仅分离 task 的托管内存。
通过调整 task slot 的数量,用户可以定义 subtask 如何互相隔离。每个 TaskManager 有一个 slot,这意味着每个 task 组都在单独的 JVM 中运行(例如,可以在单独的容器中启动)。具有多个 slot 意味着更多 subtask 共享同一 JVM。同一 JVM 中的 task 共享 TCP 连接(通过多路复用)和心跳信息。它们还可以共享数据集和数据结构,从而减少了每个 task 的开销。
默认情况下,Flink 允许 subtask 共享 slot,即便它们是不同的 task 的 subtask,只要是来自于同一作业即可。结果就是一个 slot 可以持有整个作业管道。允许slot 共享有两个主要优点:
- Flink 集群所需的 task slot 和作业中使用的最大并行度恰好一样。无需计算程序总共包含多少个 task(具有不同并行度)。
- 容易获得更好的资源利用。如果没有 slot 共享,非密集 subtask( source/map() )将阻塞和密集型 subtask( window ) 一样多的资源。通过 slot 共享,我们示例中的基本并行度从 2 增加到 6,可以充分利用分配的资源,同时确保繁重的 subtask 在 TaskManager 之间公平分配。
三、Flink 三种提交作业模式对比
3.1 概述
Flink 应用程序是从其 main() 方法产生的一个或多个 Flink 作业的任何用户程序。这些作业的执行可以在本地 JVM(LocalEnvironment)中进行,或具有多台机器的集群的远程设置(RemoteEnvironment)中进行。对于每个程序,ExecutionEnvironment 提供了一些方法来控制作业执行(例如设置并行度)并与外界交互。
Flink 应用程序的作业可以被提交到长期运行的 Flink Session 集群、专用的 Flink Job 集群 或 Flink Application 集群。这些选项之间的差异主要与集群的生命周期和资源隔离保证有关。
3.2 Flink Session 集群
- 集群生命周期:在 Flink Session 集群中,客户端连接到一个预先存在的、长期运行的集群,该集群可以接受多个作业提交。即使所有作业完成后,集群(和 JobManager)仍将继续运行直到手动停止 session 为止。因此,Flink Session 集群的寿命不受任何 Flink 作业寿命的约束。
- **资源隔离 :**TaskManager slot 由 ResourceManager 在提交作业时分配,并在作业完成时释放。由于所有作业都共享同一集群,因此在集群资源方面存在一些竞争 --- 例如提交工作阶段的网络带宽。此共享设置的局限性在于,如果 TaskManager 崩溃,则在此 TaskManager 上运行 task 的所有作业都将失败;类似的,如果 JobManager 上发生一些致命错误,它将影响集群中正在运行的所有作业。
- **其他注意事项:**拥有一个预先存在的集群可以节省大量时间申请资源和启动 TaskManager。有种场景很重要,作业执行时间短并且启动时间长会对端到端的用户体验产生负面的影响 --- 就像对简短查询的交互式分析一样,希望作业可以使用现有资源快速执行计算。
提示:Flink Session 集群也被称为 *session 模式*下的 Flink 集群。
3.3 Flink Job 集群
- **集群生命周期 :**在 Flink Job 集群中,可用的集群管理器(例如 YARN)用于为每个提交的作业启动一个集群,并且该集群仅可用于该作业。在这里,客户端首先从集群管理器请求资源启动 JobManager,然后将作业提交给在这个进程中运行的 Dispatcher。然后根据作业的资源请求惰性的分配 TaskManager。一旦作业完成,Flink Job 集群将被拆除。
- 资源隔离 :JobManager 中的致命错误仅影响在 Flink Job 集群中运行的一个作业。
- 其他注意事项:由于 ResourceManager 必须应用并等待外部资源管理组件来启动 TaskManager 进程和分配资源,因此 Flink Job 集群更适合长期运行、具有高稳定性要求且对较长的启动时间不敏感的大型作业。
提示:Flink Job 集群也被称为 job (or per-job) 模式下的 Flink 集群。并且Kubernetes 不支持 Flink Job 集群。
3.4 Flink Application 集群
- 集群生命周期:Flink Application 集群是专用的 Flink 集群,仅从 Flink 应用程序执行作业,并且 main()方法在集群上而不是客户端上运行。提交作业是一个单步骤过程:无需先启动 Flink 集群,然后将作业提交到现有的 session 集群;相反,将应用程序逻辑和依赖打包成一个可执行的作业 JAR 中,并且集群入口(ApplicationClusterEntryPoint)负责调用 main()方法来提取 JobGraph。例如,这允许你像在 Kubernetes 上部署任何其他应用程序一样部署 Flink 应用程序。因此,Flink Application 集群的寿命与 Flink 应用程序的寿命有关。
- 资源隔离 :在 Flink Application 集群中,ResourceManager 和 Dispatcher 作用于单个的 Flink 应用程序,相比于 Flink Session 集群,它提供了更好的隔离。
提示:Flink Job 集群可以看做是 Flink Application 集群"客户端运行"的替代方案。
今天Flink相关内容的介绍就分享到这里,可以关注Flink专栏《Flink》,后续不定期分享相关技术文章。如果帮助到大家,欢迎大家点赞+关注+收藏,有疑问也欢迎大家评论留言!