flink运行模式
# Flink介绍
Apache Flink 是一个框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行,并能以内存速度和任意规模进行计算
# Flink 架构图
Flink 架构图跟常见的大数据组件类似,都是采用主流的主从架构,一个 JobManager,多个 TaskManager,并可对JobManager进行HA部署。
Flink 代码从提交到真正执行,需要经过几次 Graph 图的转换,过程如下: StreamGraph -> JobGraph -> ExecutionGraph -> 物理执行图
- 第一层 StreamGraph 从 Source 节点开始,每一次 transform 生成一个 StreamNode,两个 StreamNode 通过 StreamEdge 连接在一起,形成 StreamNode 和 StreamEdge 构成的DAG。
- 第二层 JobGraph,依旧从 Source 节点开始,然后去遍历寻找能够嵌到一起的 operator,如果能够嵌到一起则嵌到一起,不能嵌到一起的单独生成 jobVertex,通过 JobEdge 链接上下游 JobVertex,最终形成 JobVertex 层面的 DAG。
- JobVertex DAG 提交到任务以后,从 Source 节点开始排序,根据 JobVertex 生成ExecutionJobVertex,根据 jobVertex的IntermediateDataSet 构建 IntermediateResult,然后 IntermediateResult 构建上下游的依赖关系,形成 ExecutionJobVertex 层面的 DAG 即 ExecutionGraph。
- 最后通过 ExecutionGraph 层到物理执行层。
# Flink 三种模式
# Session模式
Session模式是预分配资源的,也就是提前根据指定的资源参数初始化一个Flink集群,并常驻在YARN系统中,拥有固定数量的JobManager和TaskManager(注意JobManager只有一个)。提交到这个集群的作业可以直接运行,免去每次分配资源的overhead。但是Session的资源总量有限,多个作业之间又不是隔离的,故可能会造成资源的争用;如果有一个TaskManager宕机,它上面承载着的所有作业也都会失败。另外,启动的作业越多,JobManager的负载也就越大。所以,Session模式一般用来部署那些对延迟非常敏感但运行时长较短的作业。
多个 Job 提交共享同一个 JobManager,Flink Cluster的实例已经被创建,并被所有Job共享的。Flink任务由Client提交,client做一些预备工作, 并在 Flink Client 上生成 JobGraph。
缺点:一个Job导致的JobManager失败可能会导致所有的Job失败。
# Per-Job模式
顾名思义,在Per-Job模式下,每个提交到YARN上的作业会各自形成单独的Flink集群,拥有专属的JobManager和TaskManager。可见,以Per-Job模式提交作业的启动延迟可能会较高,但是作业之间的资源完全隔离,一个作业的TaskManager失败不会影响其他作业的运行,JobManager的负载也是分散开来的,不存在单点问题。当作业运行完成,与它关联的集群也就被销毁,资源被释放。所以,Per-Job模式一般用来部署那些长时间运行的作业。
为每次 Job 提交启动专用 JM,JM 将只执行此作业,然后退出。在 Flink Client 上生成 JobGraph,
可以理解为 Client 模式的Application Mode,这种模式充分利用资源管理框架的优势,例如Yarn,Mesos等,达到更强的资源隔离性,flink应用之间不会相互影响。一个Job一个Cluster实例。
以上两种模式存在问题:
Deployer代表向YARN集群发起部署请求的节点,一般来讲在生产环境中,也总有这样一个节点作为所有作业的提交入口(即客户端)。在main()方法开始执行直到env.execute()方法之前,客户端也需要做一些工作,即:
- 获取作业所需的依赖项;
- 通过执行环境分析并取得逻辑计划,即StreamGraph→JobGraph;
- 将依赖项和JobGraph上传到集群中。
只有在这些都完成之后,才会通过env.execute()方法触发Flink运行时真正地开始执行作业。试想,如果所有用户都在Deployer上提交作业,较大的依赖会消耗更多的带宽,而较复杂的作业逻辑翻译成JobGraph也需要吃掉更多的CPU和内存,客户端的资源反而会成为瓶颈——不管Session还是Per-Job模式都存在此问题。为了解决它,社区在传统部署模式的基础上实现了Application模式。
# Application模式
Flink提交的程序,被当做集群内部Application,不再需要Client端做繁重的准备工作例如执行main函数数,生成JobGraph,下载依赖并分发到各个节点等),main函数被提交给JobManager执行。一个Application一个Cluster实例。
可见,原本需要客户端做的三件事被转移到了JobManager里,也就是说main()方法在集群中执行(入口点位于ApplicationClusterEntryPoint),Deployer只需要负责发起部署请求了。另外,如果一个main()方法中有多个env.execute()/executeAsync()调用,在Application模式下,这些作业会被视为属于同一个应用,在同一个集群中执行(如果在Per-Job模式下,就会启动多个集群)。可见,Application模式本质上是Session和Per-Job模式的折衷。