Flink是一个分布式系统,需要有效地分配和管理计算资源才能执行流应用程序。它集成了所有常见的集群资源管理器,如Hadoop YARN和Kubernetes,但也可以设置为作为一个独立的集群运行,甚至作为一个库。
Flink集群的剖析
Flink运行时由两种类型的进程组成:一个JobManager和一个或多个taskmanager。
Client(客户端)不是运行时和程序执行的一部分,而是用于准备和发送数据流到JobManager。之后,客户端可以断开连接(分离模式),或者保持连接以接收进度报告(附加模式)。Client(客户端)要么作为触发执行的Java/Scala程序的一部分运行,要么在命令行进程中运行:/bin/flink run ....
JobManager和taskmanager可以通过多种方式启动:直接在机器上作为独立集群启动,在容器中启动,或者由YARN等资源框架管理。taskmanager连接到jobmanager,并通知jobmanager,当前taskmanager可用。
JobManager
JobManager有许多与协调Flink应用程序的分布式执行相关的职责:它决定何时调度下一个任务(或一组任务),对完成的任务或执行失败做出反应,协调检查点,协调故障恢复,等等。
这个过程包括三个不同的部分:
ResourceManager:负责Flink集群中的资源分配和供应——它管理task slots(任务槽),task slots(任务槽)是Flink集群中资源调度的单位。Flink为不同的环境和资源提供商(如YARN、Kubernetes和独立部署)实现了多个resourcemanager。在独立设置中,ResourceManager只能分配可用的taskmanager槽位,不能自己启动新的taskmanager。
Dispatcher:提供了一个REST接口来提交Flink应用程序以供执行,并为每个提交的作业启动一个新的JobMaster。它还运行Flink web以提供有关作业执行的信息。
JobMaster:负责管理单个JobGraph的执行。多个Job(作业)可以在Flink集群中同时运行,每个Job(作业)都有自己的JobMaster。
TaskManagers
taskmanager(也称为worker)执行数据流的任务,缓冲和交换数据流。
必须始终至少有一个TaskManager。TaskManager中资源调度的最小单位是Slot(任务槽)。TaskManager中Slot(任务槽)位的个数反映了并发处理任务的个数。注意,多个操作符可以在一个Slot(任务槽)中执行。
Tasks and Operator Chains
对于分布式执行,Flink将Operator(操作符)子任务链接在一起成为任务。 每个任务由一个线程执行。 将Operator(操作符)链接到任务中是一种有用的优化:它减少了线程间切换和缓冲的开销,并在减少延迟的同时提高了总体吞吐量。可以自行配置操作符链。
下图中的示例数据流由五个子任务执行,因此有五个并行线程。
Task Slots and Resources
每个worker (TaskManager)是一个JVM进程,可以在单独的线程中执行一个或多个子任务。 任务槽(Task slots)(至少一个)控制TaskManager接受多少任务。
每个任务槽(Task slots)代表TaskManager资源的一个固定子集。 例如,有三个插槽(Slot)的TaskManager将为每个插槽(Slot)分配1/3的托管内存。
分配资源意味着子任务不会与来自其他作业的子任务竞争托管内存,而是拥有一定数量的预留托管内存。 注意,这里没有发生CPU隔离; 目前,插槽(Slot)仅分隔任务的托管内存。
通过调整任务槽(Task slots)的数量,用户可以定义子任务彼此隔离的方式。 每个TaskManager有一个插槽(Slot)意味着每个任务组在单独的JVM中运行(例如,可以在单独的容器中启动)。
拥有多个插槽(Slot)意味着更多的子任务共享同一个JVM。 同一JVM中的任务共享TCP连接(通过多路复用)和心跳消息。 它们还可以共享数据集和数据结构,从而减少每个任务的开销。
默认情况下,Flink允许子任务共享插槽(Slot),即使它们是不同任务的子任务,只要它们来自相同的作业(Job)。 结果是一个槽(Slot)可以容纳作业(Job)整个的管道(pipeline)。
允许此插槽(Slot)共享有两个主要好处:
Flink集群需要的任务槽(Slot)正好与作业中使用的最高并行度相同。 不需要计算一个程序总共包含多少个任务(具有不同的并行度)。
更容易获得更好的资源利用率。如果没有槽位(Slot)共享,非密集的source/map()子任务将阻塞与资源密集的window子任务一样多的资源。 通过槽(Slot)共享,将我们示例中的基本并行度从2增加到6,可以充分利用槽(Slot)资源,同时确保繁重的子任务在taskmanager之间公平分配。
Flink Application Execution
Flink应用程序是从main()
方法中生成一个或多个Flink作业的任意用户程序。这些作业的执行可以在本地JVM (LocalEnvironment)中进行,也可以在具有多台机器的集群的远程设置中进行(RemoteEnvironment)。 对于每个程序,ExecutionEnvironment提供了控制作业执行(例如设置并行度)和与外部世界交互的方法。
Flink应用程序的作业可以提交到长时间运行的Flink会话集群、专用Flink作业集群(已弃用)或Flink应用程序集群。 这些选项之间的区别主要与集群的生命周期和资源隔离保证有关。
Flink Application Cluster
- 集群生命周期: Flink应用程序集群是一个专用的Flink集群,它只执行来自一个Flink应用程序的任务,并且
main()
方法在集群上而不是在客户端上运行。 作业提交是一个一步到位的过程:不需要先启动Flink集群,然后将作业提交到现有的集群会话; 相反,可以将应用程序逻辑和依赖项打包到一个可执行的作业JAR中,集群入口点(ApplicationClusterEntryPoint
)负责调用main()
方法来提取JobGraph。 例如,这允许您像部署Kubernetes上的任何其他应用程序一样部署Flink应用程序。 因此,Flink应用程序集群的生存期与Flink应用程序的生存期绑定在一起。 - 资源隔离: 在Flink应用程序集群中,ResourceManager和Dispatcher的作用域为单个Flink应用程序,这比Flink会话集群提供了更好的关注点分离。
官方文档:Flink Architecture