Flink on YARN 部署模式详解
本文讲解Flink on YARN的三种作业提交流程:Session模式共享集群,适合小作业;Per-Job模式为每作业启动集群;Application模式将应用逻辑在集群端执行,资源隔离性最佳,是官方推荐的生产模式。
Flink on YARN 是生产环境中最常用、最稳定的部署模式。它利用 YARN(Yet Another Resource Negotiator)作为资源管理器,让 Flink 应用能够按需获取和释放计算资源,并与其他大数据框架(如 Spark, MapReduce)共享同一个集群。
作业提交流程的核心区别在于 Flink 集群的生命周期和 main() 方法的执行位置。据此,Flink on YARN 主要分为三种模式:
- Application Mode (应用模式) - 官方推荐
- Per-Job Mode (单作业模式) - 传统模式
- Session Mode (会话模式)
下面我们将详细讲解每种模式的提交流程。
核心组件角色
在深入流程之前,先明确几个关键角色:
- Client: 你执行
flink run ...命令的机器。它负责准备作业所需的文件、与 YARN ResourceManager 交互。 - YARN ResourceManager (RM): YARN 集群的主节点,负责整个集群的资源分配和管理。
- YARN NodeManager (NM): YARN 集群中每个工作节点上的代理,负责管理该节点上的容器(Container)。
- Flink ApplicationMaster (AM): Flink on YARN 的核心。它首先由 ResourceManager 启动在一个容器中。它的职责包括:
- 作为 Flink 的 JobManager (JM)。
- 向 ResourceManager 申请更多的容器来运行 TaskManager。
- 监控 Flink 作业的执行。
- Flink TaskManager (TM): Flink 的工作节点,负责执行具体的计算任务(Task)。每个 TaskManager 运行在一个由 ApplicationMaster 申请来的 YARN 容器中。
1. Application Mode (应用模式) - 推荐
这是 Flink 1.11 版本后引入并作为首选的模式。它的核心思想是:整个 Flink 应用(包括 main() 方法)都在 YARN 集群上执行。
提交流程:
客户端提交 (Client)
- 用户在 Client 节点上执行
bin/flink run-application -t yarn-application ...命令。 - Flink Client 对命令进行简单的语法校验。
- Client 将 Flink 框架的 Jar 包、用户应用的 Jar 包以及相关依赖上传到 HDFS 等共享存储上。
- Client 向 YARN ResourceManager 发起一个“启动应用”的请求。此时,Client 的任务基本完成,可以立即退出,作业的生命周期与 Client 完全解耦。
- 用户在 Client 节点上执行
启动 ApplicationMaster (AM / JobManager)
- YARN ResourceManager 收到请求后,在集群中找到一个可用的 NodeManager,并指示它启动一个容器(Container)。
- 在这个容器内,Flink 的 ApplicationMaster 进程被启动。
在 AM 中执行应用代码
- ApplicationMaster 启动后,它会下载之前上传到 HDFS 的用户 Jar 包。
- 关键步骤: ApplicationMaster 在自己的 JVM 中直接调用用户 Jar 包的
main()方法。 main()方法中的 Flink 作业代码被执行,生成JobGraph(作业图)。
申请并启动 TaskManager
- ApplicationMaster (现在已经成为 JobManager) 根据
JobGraph分析出作业所需的资源(例如需要多少个 TaskManager)。 - JobManager 向 YARN ResourceManager 发起请求,申请 N 个容器来运行 TaskManager。
- ResourceManager 在集群中分配 N 个容器,并通知对应的 NodeManager 启动它们。
- ApplicationMaster (现在已经成为 JobManager) 根据
作业执行
- NodeManager 在分配到的容器中启动 Flink TaskManager 进程。
- TaskManager 启动后,会向 JobManager (即 ApplicationMaster) 进行注册。
- JobManager 收到所有 TaskManager 的注册后,将
JobGraph中的计算任务分发给这些 TaskManager。 - TaskManager 开始执行任务,作业正式运行。
优点:
- 资源隔离性好: 每个应用都有自己独立的 Flink Master (JobManager),一个应用的失败不会影响其他应用。
main()方法在集群端执行: 避免了客户端成为瓶颈(例如main()方法中有复杂的逻辑或需要下载大量元数据),也节省了客户端的网络带宽。- 真正的“提交后不管” (Fire and Forget): 客户端提交后即可下线,非常适合自动化调度系统。
2. Per-Job Mode (单作业模式)
这是 Application Mode 出现之前的标准模式。它和 Application Mode 很像,每个作业独享一个 Flink 集群,但main() 方法在客户端执行。
提交流程:
客户端提交 (Client)
- 用户执行
bin/flink run -t yarn-per-job ...命令。 - 关键步骤: Flink Client 在本地执行用户 Jar 包的
main()方法,生成JobGraph。 - Client 将 Flink 框架 Jar、用户 Jar 和生成的
JobGraph文件上传到 HDFS。 - Client 向 YARN ResourceManager 提交应用,请求启动 ApplicationMaster。
- 用户执行
启动 ApplicationMaster (JobManager)
- 与 Application Mode 相同,RM 在一个容器中启动 Flink AM。
启动 TaskManager
- AM (JobManager) 启动后,它不需要执行
main()方法,因为它直接从 HDFS 加载 Client 上传的JobGraph。 - 后续流程与 Application Mode 完全相同:JobManager 根据
JobGraph向 RM 申请 TaskManager 容器,TM 启动并注册,最后 JM 分发任务。
- AM (JobManager) 启动后,它不需要执行
客户端角色
- 在作业提交到 YARN 之后,客户端会持续轮询作业状态,直到作业进入
RUNNING状态或最终状态(FINISHED,FAILED),然后客户端进程退出。
- 在作业提交到 YARN 之后,客户端会持续轮询作业状态,直到作业进入
缺点:
- 客户端瓶颈: 如果
main()方法很重(例如需要连接外部服务获取配置),会消耗客户端资源并增加提交延迟。 - 网络开销:
JobGraph可能很大,需要在客户端和集群之间传输。
Per-Job Mode 正在被 Application Mode 逐渐取代。
3. Session Mode (会话模式)
这种模式下,你先在 YARN 上启动一个长期运行的 Flink 集群(一个 JobManager 和多个 TaskManager),然后可以向这个共享的集群提交多个作业。
提交流程 (分两步):
第一步:启动 Flink Session Cluster
- 客户端启动会话
- 用户执行
bin/yarn-session.sh命令。 - 这个脚本会向 YARN ResourceManager 申请启动一个 Flink 集群的 ApplicationMaster。
- 用户执行
- 集群启动
- RM 在容器中启动 Flink AM (JobManager)。
- AM 根据启动参数(例如
-n 4指定4个TaskManager)向 RM 申请固定数量的容器。 - RM 分配容器,TaskManager 在其中启动并向 JobManager 注册。
- 此时,一个 Flink 集群在 YARN 上已经准备就绪,处于“空闲”状态,等待作业提交。
yarn-session.sh客户端会打印出 JobManager 的地址并保持运行。
第二步:提交作业到已有会话
- 客户端提交作业
- 在另一个终端中,用户执行
bin/flink run ...命令(无需指定-t参数,Flink 会自动发现正在运行的 YARN 会话)。
- 在另一个终端中,用户执行
- 作业执行
- Flink Client 连接到已经运行的 Session Cluster 的 JobManager。
- Client 在本地执行
main()方法生成JobGraph,然后将其发送给 JobManager。 - JobManager 收到
JobGraph后,将任务分发给集群中已有的、可能空闲的 TaskManager。 - 作业开始在共享的 TaskManager 上执行。
优点:
- 低延迟: 对于提交大量短时间、小型的作业非常高效,因为它省去了为每个作业启动 Flink Master 和 TaskManager 的开销。
缺点:
- 资源隔离性差: 所有作业共享同一组 TaskManager。一个有问题的作业(如导致 OOM)可能会影响到同一会话中的所有其他作业。
- 资源不灵活: 集群资源是预先分配的。如果没作业,资源闲置浪费;如果作业多,资源可能成为瓶颈。
总结与对比
| 特性 | Session Mode (会话模式) | Per-Job Mode (单作业模式) | Application Mode (应用模式) |
|---|---|---|---|
| 集群生命周期 | 手动启动,长期运行,多作业共享 | 与单个作业的生命周期绑定 | 与单个应用的生命周期绑定 |
| 资源隔离 | 差,所有作业共享资源 | 好,每个作业独占集群 | 最好,每个应用独占集群 |
main() 执行位置 |
客户端 | 客户端 | 集群端 (JobManager) |
| 主要优点 | 提交小作业延迟低 | 资源隔离好 | 资源隔离好,无客户端瓶颈 |
| 主要缺点 | 资源隔离差,资源利用率不稳定 | 客户端可能成为瓶颈 | / |
| 适用场景 | 频繁执行的、短时间的临时查询/作业 | 传统的批处理或流处理作业 | 所有生产环境的流处理和批处理作业(推荐) |
总而言之,对于绝大多数生产场景,请优先选择 Application Mode。它提供了最佳的资源隔离和运维便利性。Session Mode 则更适合交互式分析和开发测试环境。