背景
最近公司在做实时数仓,技术上选择flink作为数据处理引擎,同时需要将实时数仓cdc(ODS层),建模(DWD)等逻辑进行功能化集成到数据仓库中方便数仓开发人员进行使用。
由于离线平台使用Yarn作为资源管理器而flink也支持yarn,为通过api进行flink应用的启动停止最终使用flink yarn application 模式进行发布。
Flink Yarn 介绍
下图为flink官方架构图,主要说明了flink 应用在yarn application模式下用户jar包的执行过程。
- 将用户uber-jar上传到hdfs,等到yarn container启动时直接通过hdfs下载
- 通过flink client 提交命令到yarn resource manger
- 分配yarn app master
- 由于flink 是主从架构且支持并行执行因此yarn会根据提交的配置启动多个yarn container 分别执行flink job manager跟task mananger
当然flink standalone 模式提供了rest api可以控制flink jar的执行但不是我们的需求所以放弃
中台集成架构
由于中台使用springcloud 架构且只负责flink 用户jar的启动发布与监控管理因此通过flink cli 源码进行分析后将相关逻辑进行整理并与中台集成如下图所示
- 通过平台将flink 用户jar 名称,启动参数等进行管理
- 通过yarn api 提交用户jar 到yarn集群
- flink 用户应用通过http回调可以自定义配置信息并执行
以上逻辑是在分析完flink cli 启动逻辑后将代码
Flink CLI 启动源码分析
下图为flink 启动脚本对应的源代码逻辑
- 启动入口为CliFrontend主函数
- 加载配置信息命令行信息
- 根据传入参数使用那种命令模式
- 由于本文为application mode 所以通过yarn进行发布这也是中台中需要的逻辑
- 通过JAVA SPI进行加载要执行的deployer
- 最终将应用发布到yarn
代码演示
核心代码逻辑如下,具体jar包版本需要根据实际情况进行分析并调整
String flinkLibs = "hdfs://GWNS/tmp/lib";
String userJarPath = "hdfs://GWNS/tmp/lib/WordCount.jar";
String flinkDistJar = "hdfs://GWNS/tmp/lib/flink-dist_2.12-1.12.0.jar";
YarnClient yarnClient = YarnClient.createYarnClient();
YarnConfiguration yarnConfiguration = new YarnConfiguration();
yarnClient.init(yarnConfiguration);
yarnClient.start();
YarnClusterInformationRetriever clusterInformationRetriever = YarnClientYarnClusterInformationRetriever
.create(yarnClient);
//获取flink的配置
Configuration flinkConfiguration = GlobalConfiguration.loadConfiguration(
configurationDirectory);
// flinkConfiguration.set(CheckpointingOptions.INCREMENTAL_CHECKPOINTS, true);
flinkConfiguration.set(
PipelineOptions.JARS,
Collections.singletonList(
userJarPath));
YarnLogConfigUtil.setLogConfigFileInConfig(flinkConfiguration,configurationDirectory);
Path remoteLib = new Path(flinkLibs);
flinkConfiguration.set(
YarnConfigOptions.PROVIDED_LIB_DIRS,
Collections.singletonList(remoteLib.toString()));
flinkConfiguration.set(
YarnConfigOptions.FLINK_DIST_JAR,
flinkDistJar);
//设置为application模式
flinkConfiguration.set(
DeploymentOptions.TARGET,
YarnDeploymentTarget.APPLICATION.getName());
//yarn application name
flinkConfiguration.set(YarnConfigOptions.APPLICATION_NAME, "test-yarn-api");
//设置配置,可以设置很多
flinkConfiguration.set(JobManagerOptions.TOTAL_PROCESS_MEMORY, MemorySize.parse("1024",MEGA_BYTES));
flinkConfiguration.set(TaskManagerOptions.TOTAL_PROCESS_MEMORY, MemorySize.parse("1024",MEGA_BYTES));
ClusterSpecification clusterSpecification = new ClusterSpecification.ClusterSpecificationBuilder()
.createClusterSpecification();
// 设置用户jar的参数和主类
ApplicationConfiguration appConfig = new ApplicationConfiguration(params,"org.apache.flink.examples.java.wordcount.WordCount");
YarnClusterDescriptor yarnClusterDescriptor = new YarnClusterDescriptor(
flinkConfiguration,
yarnConfiguration,
yarnClient,
clusterInformationRetriever,
true);
ClusterClientProvider<ApplicationId> clusterClientProvider = null;
try {
clusterClientProvider = yarnClusterDescriptor.deployApplicationCluster(clusterSpecification,appConfig);
} catch (ClusterDeploymentException e){
e.printStackTrace();
}
本方案目前已经在公司得到验证,同时欢迎更多交流