一.背景
在企业级实时大数据处理场景中,Apache Flink 凭借低延迟、高吞吐的流处理能力,成为日志分析、实时计算、事件驱动型应用的核心引擎;而 YARN 作为 Hadoop 生态的主流资源调度系统,是企业私有化大数据集群的标准资源管理底座。Flink YARN Session 模式通过预先申请集群资源并启动常驻的 Flink 集群(Session Cluster),可复用资源承接多个作业提交,相比 Per-Job 模式大幅降低资源申请与集群启动的开销,适配高频、小规模作业的运行诉求。但传统的 Flink YARN Session 作业发布方式(如 flink run 命令行、脚本化提交)已难以满足企业对 "标准化、自动化、可管控" 的运维要求,基于 Java 实现程序化发布 Flink YARN Session 作业,成为解决传统痛点、适配企业级落地的核心选择。
1.传统 Flink YARN Session 作业发布的核心痛点
-
发布流程碎片化,自动化能力不足 传统发布依赖
flink run -m yarn-session://<yarn-jobmanager-addr>命令行手动执行,或通过 Shell 脚本封装参数,存在显著短板:一是参数配置繁琐(如指定 YARN Session 地址、作业并行度、内存配额、依赖包、主类等),易因参数拼写错误、版本不兼容导致作业提交失败;二是难以集成至企业 CI/CD 流水线、运维平台等自动化体系,大量依赖人工操作,发布效率低且易引发人为故障;三是测试 / 生产等多环境的配置(如 YARN 队列、资源大小、数据源地址)需手动修改脚本,缺乏统一的配置管理机制,环境一致性难以保障。 -
Session 集群与作业管控能力缺失
flink run仅能完成作业 "提交" 动作,无法程序化管控 YARN Session 集群及作业全生命周期:提交后无法实时获取作业在 Session 集群中的运行状态(RUNNING/FAILED/CANCELED)、资源使用情况;作业异常时无法自动重试或触发告警;需人工登录 Flink WebUI、YARN ResourceManager 控制台查询状态,运维成本高,且无法快速响应作业故障;同时,对 YARN Session 集群的创建、销毁、资源扩容等操作也需手动执行,无法根据作业负载动态调整。 -
与企业级系统集成性差 企业级场景中,作业发布需对接权限管控、资源审批、日志审计、成本计量等系统,但
flink run作为独立命令行工具,无法直接联动这些系统:例如,提交前无法校验用户是否有 YARN Session 所在队列的使用权限,提交后无法自动记录作业的资源消耗用于成本核算,作业日志无法自动归集至企业统一日志平台,难以满足合规与精细化运维诉求。 -
多 Session 集群 / 多版本适配困难 企业往往部署多套 YARN Session 集群(如测试 / 生产、不同业务专属集群)、多个 Flink 版本,传统脚本化发布需为不同集群 / 版本维护不同的
flink run脚本,版本兼容、集群地址切换成本高;且无法程序化识别 YARN Session 集群的可用状态,易将作业提交至异常的 Session 集群,导致作业运行失败。
2.Java 实现发布 Flink YARN Session 作业的核心价值
Java 作为 Flink 底层开发的核心语言,也是企业级应用开发的主流语言,基于 Java 实现 Flink YARN Session 作业的程序化发布,本质是构建 "标准化、自动化、可管控" 的作业发布体系,解决传统方式的痛点:
-
标准化发布接口,提升自动化水平 基于 Flink 官方提供的
FlinkYarnSessionCli、ClusterClient等 Java API 封装统一的发布接口,将 YARN Session 作业的核心配置(Session 集群地址、主类、jar 包路径、并行度、内存配额、YARN 队列等)抽象为可配置参数,替代碎片化的flink run命令。该接口可无缝集成至企业 CI/CD 流水线(Jenkins、GitLab CI)、大数据调度平台,实现 "代码编译 - 打包 - 作业发布 - 状态校验" 的全流程自动化,减少人工干预,降低发布错误率。 -
全生命周期管控,强化运维能力Java 程序可通过 Flink Rest API、YARN ResourceManager REST API 联动 Session 集群与作业:提交作业后实时监听作业状态,捕获运行异常、失败、终止等状态变更;作业失败时自动触发重试逻辑,或推送告警至企业监控平台(如 Prometheus、AlertManager);作业运行中可查询并行度、CPU / 内存使用情况,拉取作业日志并归集至 ELK 等统一日志系统;同时可程序化管理 YARN Session 集群,根据作业负载动态创建、销毁、扩容 Session 集群,提升资源利用率。
-
深度集成企业级系统,满足合规诉求Java 发布程序可对接企业现有系统:提交作业前调用权限系统校验用户 / 应用对 YARN 队列、Flink Session 集群的使用权限;提交过程中记录审计日志(提交人、时间、配置、集群信息),满足合规审计要求;作业运行后将资源消耗数据同步至成本计量系统,实现作业成本的精细化核算;同时可集成 Nacos、Apollo 等配置中心,统一管理多环境配置,避免手动修改脚本导致的配置不一致问题。
-
灵活适配多集群 / 多版本场景通过 Java 程序的配置化设计,将不同 YARN Session 集群的连接信息(JobManager 地址、YARN ResourceManager 地址)、不同 Flink 版本的适配参数封装为配置项,发布作业时按需加载对应配置,无需修改核心代码即可适配多集群、多版本场景。例如,通过配置中心切换测试 / 生产 Session 集群地址,一键发布作业至目标集群,降低环境适配成本。
3.典型应用场景
- 企业级实时计算平台作业发布:构建统一的 Flink 实时计算平台,基于 Java 实现 YARN Session 作业的标准化发布入口,支撑各业务部门提交实时日志分析、交易风控、用户行为计算等作业,统一管控 Session 集群资源、作业权限、运行日志,提升平台易用性与可维护性。
- 高频小作业的高效发布:零售、互联网等行业的实时指标计算、实时告警等高频小作业,通过 Java 程序发布至常驻的 YARN Session 集群,复用集群资源避免重复申请,降低作业启动延迟,保障实时计算的低延迟诉求。
- 多 Session 集群的统一管控:企业为不同业务线部署专属 YARN Session 集群,通过 Java 程序实现作业的批量发布、状态统一监控,适配业务隔离与资源按需分配的需求,同时支持跨集群作业容灾切换。
- 业务系统触发的实时计算:订单系统、支付系统等业务系统触发实时数据计算需求时,通过 Java 接口直接发布 Flink YARN Session 作业,作业完成后将计算结果回调至业务系统,实现 "业务触发 - 实时计算 - 结果返回" 的闭环。
综上,Java 实现发布 Flink YARN Session 模式作业,是企业将 Flink 实时计算能力从 "手工运维" 转向 "工程化、自动化管控" 的关键路径:既充分利用 Flink YARN Session 模式的资源复用优势,又通过 Java 语言的企业级特性,解决发布碎片化、管控缺失、集成性差等痛点,适配企业级实时大数据处理的规模化、规范化诉求,为低延迟、高吞吐的实时计算场景提供稳定、可管控的发布支撑。
二.具体实现
1.引入依赖
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-yarn</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-yarn-api</artifactId>
<version>3.2.1</version>
</dependency>
2.定义flink参数
Configuration flinkConfig = new Configuration();
flinkConfig.setString(JobManagerOptions.TOTAL_FLINK_MEMORY.key(), "1024m");
flinkConfig.setString(TaskManagerOptions.TOTAL_FLINK_MEMORY.key(), "1024m");
flinkConfig.setInteger(TaskManagerOptions.NUM_TASK_SLOTS, 4);
flinkConfig.setString(CoreOptions.FLINK_HADOOP_CONF_DIR, "/opt/teh/core/hadoop/etc/hadoop");
flinkConfig.setString(YarnConfigOptions.APPLICATION_TYPE, "Flink");
... ...
3.定义客户端
YarnClusterDescriptor clusterDescriptor = null;
PackagedProgram packageProgram = null;
ClusterClient<ApplicationId> client = null;
DefaultClusterClientServiceLoader serviceLoader = new DefaultClusterClientServiceLoader();
ClusterClientFactory<ApplicationId> clientFactory = serviceLoader.getClusterClientFactory(flinkConfig);
ApplicationId yarnClusterId = clientFactory.getClusterId(flinkConfig);
clusterDescriptor = (YarnClusterDescriptor) clientFactory.createClusterDescriptor(flinkConfig);
4.定义flink作业的配置
List<String> argList = flinkConfig
.getOptional(ApplicationConfiguration.APPLICATION_ARGS)
.orElse(Lists.newArrayList());
SavepointRestoreSettings srs = SavepointRestoreSettings.forPath("");
packageProgram = PackagedProgram.newBuilder()
.setArguments(argList.toArray(new String[argList.size()]))
.setEntryPointClassName(
flinkConfig.getOptional(ApplicationConfiguration.APPLICATION_MAIN_CLASS).get()
)
.setSavepointRestoreSettings(srs)
.build();
JobGraph jobGraph = PackagedProgramUtils.createJobGraph(
packageProgram,
flinkConfig,
10,
null,
false
);
5.发布作业
client = clusterDescriptor.retrieve(yarnClusterId).getClusterClient();
String jobId = client.submitJob(jobGraph).get().toString();
String jobManagerUrl = client.getWebInterfaceURL();