Spark程序的Yarn集群提交流程源码分析(一)

sparkYarn集群提交流程分析(一)

  • spark提交流程图简介(之后的源码分析会围绕流程图进行)
    在这里插入图片描述

源码分析

注意: 本文章中的所有代码都不完整 , 这里只取了重要代码分析

  • 1 .首先集群提交就需要将用户编写的应用程序打成jar包上传到集群中
  • 2 .其次在集群中执行的代码如下:
	bin/spark-submit \
	--class com.project.spark.WordCount \
	--master yarn \
	WordCount.jar \
	/input \
	/output
	#注意: 这里的 \代表换行
  • 3 .这里我们执行的是spark中bin目录下的spark-submit文件,文件中的代码主要是执行bin目录下的spark-class
	exec "${SPARK_HOME}"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@"
	#这里实际上执行的就是bin目录下的另一个文件spark-class

  • 4 .在spark-class文件中总结出来的重要代码是
	# Find the java binary
	if [ -n "${JAVA_HOME}" ]; then
	  RUNNER="${JAVA_HOME}/bin/java"
	else
	  if [ "$(command -v java)" ]; then
	    RUNNER="java"
	  else
	    echo "JAVA_HOME is not set" >&2
	    exit 1
	  fi
	fi
	

	build_command() {
	  "$RUNNER" -Xmx128m -cp "$LAUNCH_CLASSPATH" org.apache.spark.launcher.Main "$@"
	  printf "%d\0" $?
	}
	
	CMD=()
	while IFS= read -d '' -r ARG; do
	  CMD+=("$ARG")
	done < <(build_command "$@")

	CMD=("${CMD[@]:0:$LAST}")
	exec "${CMD[@]}"
1) . 获取java环境变量,然后拼接执行脚本/bin/java
2) . 加上参数封装执行第一个类org.apache.spark.launcher.Main将返回的数据封装到CMD中,实际上的作用就是对命令进行封装
3) . 最终大概可以得出的真实命令就是
	${JAVA_HOME}/bin/java org.apache.spark.deploy.SparkSubmit "$@"
  • 5 .实际上就是执行SparkSubmit类的main方法,至此就开始真正的源码分析 , 但是另外需要一些操作

查看源码需要在Maven项目中加入如下依赖,或者非Maven项目手动导入jar包

 		<!--读取yarn集群模式启动的程序源码-->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-yarn_2.11</artifactId>
            <version>2.1.1</version>
        </dependency>
  • 5.1 bin/java执行的是SparkSubmit伴生类中的main方法 , 回顾java中的进程线程相关知识
  1. Java中main方法启动的是一个线程也是一个进程,一个java程序启动后它就是一个进程
  2. 这样的结论在scala中同样适用
1) 这样就可以得出提交命令首先在应用程序所在的集群开启了一个SparkSubmit进程,如下就是SparkSubmit的主函数
	//这是org.apache.spark.deploy.SparkSubmit的main

	def main(args: Array[String]): Unit = {
	//将参数整合起来封装到Bean对象中一遍操作
    val appArgs = new SparkSubmitArguments(args)
    if (appArgs.verbose) {
      printStream.println(appArgs)
    }
	//这里是主要代码,具体操作要根据appArgs.action来决定
    appArgs.action match {
      case SparkSubmitAction.SUBMIT => submit(appArgs)
      case SparkSubmitAction.KILL => kill(appArgs)
      case SparkSubmitAction.REQUEST_STATUS => requestStatus(appArgs)
    }
  }
  • 5.1.1 由于模式匹配决定下一步的走向,模式匹配又依赖appArgs.action的值,这个值被封装在SparkSubmitArguments对象中,进入到SparkSubmitArguments类中找到appArgs.action的值
	//这个方法存在主构造器中会主动被调用
  private def loadEnvironmentArguments(): Unit = {
    ...
    //这里会对action这个属性进行初始化
    action = Option(action).getOrElse(SUBMIT)
  }
1) 在SparkSubmitArguments的主构造器中会主动地调用`loadEnvironmentArguments()`方法,方法中会对`action`进行赋值
  • 5.1.2 获得了action的值是SUBMIT之后就会根据模式匹配进入submit()方法中,主要代码如下:
	private def submit(args: SparkSubmitArguments): Unit = {
	    val (childArgs, childClasspath, sysProps, childMainClass) = prepareSubmitEnvironment(args)
	
	    def doRunMain(): Unit = {
	      if (args.proxyUser != null) {
	        ....
	      } else {
	        runMain(childArgs, childClasspath, sysProps, childMainClass, args.verbose)
	      }
	    }
	
	    if (args.isStandaloneCluster && args.useRest) {
	     ...
	    } else {
	      doRunMain()
	    }
  }
1) 首先看 if (args.isStandaloneCluster && args.useRest) 代码,因为在这里是Yarn集群提交的所以走 doRunMain() 方法
2) doRunMain方法中 args.proxyUser 一般没有,所以走 runMain() 方法
3) 最后我们要记住上面代码中 childMainClass 的具体值以后会使用的到,prepareSubmitEnvironment(args)中的相关代码
	  ....
	  if (isYarnCluster) {
      	childMainClass = "org.apache.spark.deploy.yarn.Client"
      ....
4) 我们可以得到 childMainClass 的值为 org.apache.spark.deploy.yarn.Client
  • 5.1.2.1 从submit()进入runMain()后的主要代码如下
	//根据字符串类型的类全限定名获取类对象
	~ Class.forName(childMainClass)
	//根据类对象获取当前类的main方法
	~val mainMethod = mainClass.getMethod("main")
	//调用指定类的主方法
	~mainMethod.invoke(null, childArgs.toArray)
1) 从5.1.2 中的 4) 可以得到 childMainClass为 org.apache.spark.deploy.yarn.Client 由此可知此时程序将会执行 org.apache.spark.deploy.yarn.Client的main方法
  • 6 这篇文章主要讲的是应用程序 --> 提交到集群本地创建SparkSubmit进程 --> 执行org.apache.spark.deploy.yarn.Client的main方法

转下一篇

(二) https://blog.csdn.net/long_World/article/details/114984564

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值