flink源码解读--3 CliFrontend.run

参考文档:https://blog.csdn.net/weixin_43161811/article/details/103152867

入口命令(参看第一篇文章):

java  ClientFrontend run -c  com.tclking.ai.PVUVDayMain   -m yarn-cluster examples/batch/WordCount.jar

ClientFrontend.main-->cli.parseParameters(args) // Line 1083 --->run(args)

代码如下:

protected void run(String[] args) throws Exception { LOG.info("Running 'run' command.");   //构建新的options即commandOptions: 如下代码会调用CliFrontendParser.getProgramSpecificOptions相关添加 option   
 //     options.addOption(JAR_OPTION);   new Option("j", "jarfile", true, "Flink program JAR file.");
 //     options.addOption(CLASS_OPTION);  new Option("c", "class", true,    "Class with the program entry point 
 //       options.addOption(CLASSPATH_OPTION);new Option("C", "classpath", true, "Adds a URL to each user code classloader  on all nodes in the cluster.
  //      options.addOption(PARALLELISM_OPTION);new Option("p", "parallelism", true,"The parallelism with which to run the program. Optional flag to override the default value
 //       options.addOption(ARGS_OPTION);   new Option("a", "arguments", true,"Program arguments. Arguments can also be added without -a, simply as trailing parameters.")
 //      options.addOption(LOGGING_OPTION);  new Option("q", "sysoutLogging", false, "If present, suppress logging output to standard out.");
 //       options.addOption(DETACHED_OPTION); new Option("d", "detached", false, "If present, runs the job in detached mode")
 //       options.addOption(SHUTDOWN_IF_ATTACHED_OPTION);new Option("sae", "shutdownOnAttachedExit", false"If the job is submitted in attached mode, perform a best-effort cluster shutdown " 
 //       options.addOption(YARN_DETACHED_OPTION);
 //       options.addOption(PY_OPTION);
 //       options.addOption(PYFILES_OPTION);
  //      options.addOption(PYMODULE_OPTION);
 //      options.addOption(SAVEPOINT_PATH_OPTION)new Option("s", "fromSavepoint", true,"Path to a savepoint to restore the job from (for example hdfs:///flink/savepoint-1537).")
 //      options.addOption(SAVEPOINT_ALLOW_NON_RESTORED_OPTION);new Option("n", "allowNonRestoredState", false
 final Options commandOptions = CliFrontendParser.getRunCommandOptions();   

//合并commandOptions和customCommandLineOptions,
//customCommandLineOptions 在new CliFrontend时Line 131, new options,然后遍历customCommandLines即FlinkYarnSessionCli和DefaultCLI得到
// addOption(addressOption) ;             //new Option("m", "jobmanager", true,"Address of the JobManager (master) to which to connect. ") 
// addOption(zookeeperNamespaceOption);    //new Option("z", "zookeeperNamespace", true,"Namespace to create the Zookeeper sub-paths for high availability mode");
// addOption(applicationId);             //new Option(shortPrefix + "id", longPrefix + "applicationId", true, "Attach to running YARN session");
// 并添加FlinkYarnSessionCli的addRunOptions即FlinkYarnSessionCli构造时,所有的option,参看210行
//类似: new Option(shortPrefix + "nm", longPrefix + "name", true, "Set a custom name for the application on YARN");

final Options commandLineOptions = CliFrontendParser.mergeOptions(commandOptions, customCommandLineOptions);

//args即为 命令行提交的参数: run -c  com.tclking.ai.PVUVDayMain   -m yarn-cluster examples/batch/WordCount.jar
// 实际调用并返回: DefaultParser.parse(commandLineOptions, args, true)
   final CommandLine commandLine = CliFrontendParser.parse(commandLineOptions, args, true);

//commandLine构造RunOptions
   final RunOptions runOptions = new RunOptions(commandLine);

   // evaluate help flag
   if (runOptions.isPrintHelp()) {
      CliFrontendParser.printHelpForRun(customCommandLines);
      return;
   }

   if (!runOptions.isPython()) {
      // Java program should be specified a JAR file
      if (runOptions.getJarFilePath() == null) {
         throw new CliArgsException("Java program should be specified a JAR file.");
      }
   }

   final PackagedProgram program;
   try {
      LOG.info("Building program from JAR file");
      program = buildProgram(runOptions);
   }
   catch (FileNotFoundException e) {
      throw new CliArgsException("Could not build the program from JAR file.", e);
   }





    //
   //  遍历customCommandLine:即FlinkYarnSessionCli和DefaultCLI,判断active(参数commandLine)
 // 判断-m参数是否等于yanr-cluster,为true返回FlinkYarnSessionCli
   final CustomCommandLine<?> customCommandLine = getActiveCustomCommandLine(commandLine);

   try {
      runProgram(customCommandLine, commandLine, runOptions, program);
   } finally {
      program.deleteExtractedLibraries();
   }
}

 

 

 

 

// buildProgram主要构建PackagedProgram:  jar 路径,classpath,入口类entryPointClass, 参数,PackagedProgram buildProgram(ProgramOptions options) throws FileNotFoundException, ProgramInvocationException {
   String[] programArgs = options.getProgramArgs();
   String jarFilePath = options.getJarFilePath();
   List<URL> classpaths = options.getClasspaths();

   // Get assembler class
   String entryPointClass = options.getEntryPointClassName();
   File jarFile = null;
   if (options.isPython()) {
      // If the job is specified a jar file
      if (jarFilePath != null) {
         jarFile = getJarFile(jarFilePath);
      }

      // If the job is Python Shell job, the entry point class name is PythonGateWayServer.
      // Otherwise, the entry point class of python job is PythonDriver
      if (entryPointClass == null) {
         entryPointClass = "org.apache.flink.client.python.PythonDriver";
      }
   } else {
      if (jarFilePath == null) {
         throw new IllegalArgumentException("Java program should be specified a JAR file.");
      }
      jarFile = getJarFile(jarFilePath);
   }

   PackagedProgram program = entryPointClass == null ?
         new PackagedProgram(jarFile, classpaths, programArgs) :
         new PackagedProgram(jarFile, classpaths, entryPointClass, programArgs);

   program.setSavepointRestoreSettings(options.getSavepointRestoreSettings());

   return program;
}

 核心逻辑: runProgram(customCommandLine, commandLine, runOptions, program);

 // customCommandLine为 FlinkYarnSessionCli实例 

 // commandLine为

private <T> void runProgram(
			CustomCommandLine<T> customCommandLine,
			CommandLine commandLine,
			RunOptions runOptions,
			PackagedProgram program) throws ProgramInvocationException, FlinkException {
       //   根据用户命令行参数,创建ClusterDescriptor,ClusterDescriptor是一个集群属性的描述对象,
       //  	用于部署集群(例如 Yarn、Mesos),并且返回一个与集群通信的客户端
       // customCommandLine为 FlinkYarnSessionCli实例。具体参看明细1
       final ClusterDescriptor<T> clusterDescriptor = customCommandLine.createClusterDescriptor(commandLine);

		try {

			final T clusterId = customCommandLine.getClusterId(commandLine);

			final ClusterClient<T> client;

			// directly deploy the job if the cluster is started in job mode and detached
			if (clusterId == null && runOptions.getDetachedMode()) {
				int parallelism = runOptions.getParallelism() == -1 ? defaultParallelism : runOptions.getParallelism();

				final JobGraph jobGraph = PackagedProgramUtils.createJobGraph(program, configuration, parallelism);

				final ClusterSpecification clusterSpecification = customCommandLine.getClusterSpecification(commandLine);
				client = clusterDescriptor.deployJobCluster(
					clusterSpecification,
					jobGraph,
					runOptions.getDetachedMode());

				logAndSysout("Job has been submitted with JobID " + jobGraph.getJobID());

				try {
					client.shutdown();
				} catch (Exception e) {
					LOG.info("Could not properly shut down the client.", e);
				}
			} else {
				final Thread shutdownHook;
				if (clusterId != null) {
					client = clusterDescriptor.retrieve(clusterId);
					shutdownHook = null;
				} else {
					// also in job mode we have to deploy a session cluster because the job
					// might consist of multiple parts (e.g. when using collect)
					final ClusterSpecification clusterSpecification = customCommandLine.getClusterSpecification(commandLine);
					client = clusterDescriptor.deploySessionCluster(clusterSpecification);
					// if not running in detached mode, add a shutdown hook to shut down cluster if client exits
					// there's a race-condition here if cli is killed before shutdown hook is installed
					if (!runOptions.getDetachedMode() && runOptions.isShutdownOnAttachedExit()) {
						shutdownHook = ShutdownHookUtil.addShutdownHook(client::shutDownCluster, client.getClass().getSimpleName(), LOG);
					} else {
						shutdownHook = null;
					}
				}

				try {
					client.setPrintStatusDuringExecution(runOptions.getStdoutLogging());
					client.setDetached(runOptions.getDetachedMode());

					LOG.debug("{}", runOptions.getSavepointRestoreSettings());

					int userParallelism = runOptions.getParallelism();
					LOG.debug("User parallelism is set to {}", userParallelism);
					if (ExecutionConfig.PARALLELISM_DEFAULT == userParallelism) {
						userParallelism = defaultParallelism;
					}

					executeProgram(program, client, userParallelism);
				} finally {
					if (clusterId == null && !client.isDetached()) {
						// terminate the cluster only if we have started it before and if it's not detached
						try {
							client.shutDownCluster();
						} catch (final Exception e) {
							LOG.info("Could not properly terminate the Flink cluster.", e);
						}
						if (shutdownHook != null) {
							// we do not need the hook anymore as we have just tried to shutdown the cluster.
							ShutdownHookUtil.removeShutdownHook(shutdownHook, client.getClass().getSimpleName(), LOG);
						}
					}
					try {
						client.shutdown();
					} catch (Exception e) {
						LOG.info("Could not properly shut down the client.", e);
					}
				}
			}
		} finally {
			try {
				clusterDescriptor.close();
			} catch (Exception e) {
				LOG.info("Could not properly close the cluster descriptor.", e);
			}
		}
	}

明细1:customCommandLine.createClusterDescriptor(commandLine)

@Override
	public AbstractYarnClusterDescriptor createClusterDescriptor(CommandLine commandLine) throws FlinkException {
// 基于原有在flink/conf下的配置文件对象,将命令行参数为准替换配置文件设置,如jm,tm设置
		final Configuration effectiveConfiguration = applyCommandLineOptionsToConfiguration(commandLine);

// 下属方法调用getClusterDescriptor, 见明细代码2
		return createDescriptor(
			effectiveConfiguration,
			yarnConfiguration,
			configurationDirectory,
			commandLine);
	}



明细代码2:
private AbstractYarnClusterDescriptor getClusterDescriptor(
			Configuration configuration,
			YarnConfiguration yarnConfiguration,
			String configurationDirectory) {
        // 实例化 yarnClient = new YarnClientImpl()
		final YarnClient yarnClient = YarnClient.createYarnClient();

        // yarnConfiguration为直接new YarnConfigruation(),主要一些默认静态属性
        // 将配置文件的yarn属性值赋值给对象属性
		yarnClient.init(yarnConfiguration);
        
        // 1 构造资源管理器客户端 ClientRMProxy为单例,返回值赋给yarnClient 属性rmClient
this.rmClient=ClientRMProxy.createRMProxy(this.getConfig(), ApplicationClientProtocol.class)
        //  2 按RM高可用与否,返回对应的proxy,并创建RetryProxy。  参看明细3。
		yarnClient.start();

        // 构造YarnClusterDescriptor对象。参数yarnClient的rmClient属性为上述代理返回。
		return new YarnClusterDescriptor(
			configuration,
			yarnConfiguration,
			configurationDirectory,
			yarnClient,
			false);
	}

 


     明细3:ClientRMProxy根据是否高可用返回对应rmClient
     protected static <T> T createRMProxy(Configuration configuration, Class<T> protocol, RMProxy instance) throws IOException {
        YarnConfiguration conf = configuration instanceof YarnConfiguration ? (YarnConfiguration)configuration : new YarnConfiguration(configuration);
        RetryPolicy retryPolicy = createRetryPolicy(conf);
        if (HAUtil.isHAEnabled(conf)) {
         //高可用情况
            RMFailoverProxyProvider<T> provider = instance.createRMFailoverProxyProvider(conf, protocol);
            return RetryProxy.create(protocol, provider, retryPolicy);
        } else {
         // 非高可用,instance为单例ClientRMProxy,protocol=ApplicationClientProtocol
            InetSocketAddress rmAddress = instance.getRMAddress(conf, protocol);
            LOG.info("Connecting to ResourceManager at " + rmAddress);
            
           // 返回YarnRPC.create(conf).getProxy(protocol, rmAddress, conf);
           // YarnRPC.create(conf)根据conf属性"yarn.ipc.rpc.class"获取rpc类,默认值HadoopYarnProtoRPC.class
           // 获取代理HadoopYarnProtoRPC.getProxy(protocol, rmAddress, conf);
            //  先获取客户端工厂,参数yarn.ipc.client.factory.class指定,默认值是org.apache.hadoop.yarn.factories.impl.pb.RpcClientFactoryPBImpl
                // 再获取客户端:RpcClientFactoryPBImpl.getClient:实际返回ApplicationClientProtocol的客户端远程接口包装类:ApplicationClientProtocol+PBClientImpl对应的构造体(Long.TYPE, InetSocketAddress.class, Configuration.class);包名+".impl.pb.client" 
          
            T proxy = getProxy(conf, protocol, rmAddress);

            // retryPolicy为根据yarn配置文件,针对不同异常重试时间间隔策略设置
            // proxyProvider=new DefaultFailoverProxyProvider(protocol, implementation)
            // 使用动态代理:获取protocol的动态代理。实际将调用RetryInvocationHandler的invoke方法(会调用上一行返回的proxy的方法)。Proxy.newProxyInstance(proxyProvider.getInterface().getClassLoader(), new Class[]{protocol}, new RetryInvocationHandler(proxyProvider, retryPolicy));
            return RetryProxy.create(protocol, proxy, retryPolicy);
        }
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值