• spark源码(十二)sparksubmit 流程详解


    一般提交任务都是spark-submit --class org.apache.spark.examples.SparkPi 类似的
    我们下面就以这个SparkPi 完成源码的跟进

    寻找main函数类
        我们跟进一个spark命令行的样例详细看看spark的源码
        cat /opt/spark/spark/bin/spark-submit 
        拿到执行的类:org.apache.spark.deploy.SparkSubmit  继续跟进
       org.apache.spark.deploy.SparkSubmit 1017 行
        override def main(args: Array[String]): Unit = {
          val submit = new SparkSubmit() {
            self =>
            ......
            override def doSubmit(args: Array[String]): Unit = {
              try {
                super.doSubmit(args)/*还是调用了父类的方法*/
              } catch {
                case e: SparkUserAppException =>
                  exitFn(e.exitCode)
              }
            }
            ......
          }
          submit.doSubmit(args)/*中心方法*/
        }
       org.apache.spark.deploy.SparkSubmit 80行
        def doSubmit(args: Array[String]): Unit = {
          val uninitLog = initializeLogIfNecessary(true, silent = true)

          val appArgs = parseArguments(args)/*解析参数*/
          if (appArgs.verbose) {
            logInfo(appArgs.toString)
          }
          appArgs.action match {/*任务是提交  kill */
            case SparkSubmitAction.SUBMIT => submit(appArgs, uninitLog)
            case SparkSubmitAction.KILL => kill(appArgs)
            case SparkSubmitAction.REQUEST_STATUS => requestStatus(appArgs)
            case SparkSubmitAction.PRINT_VERSION => printVersion()
          }
        }
       org.apache.spark.deploy.SparkSubmit 156行
        private def submit(args: SparkSubmitArguments, uninitLog: Boolean): Unit = {
          def doRunMain(): Unit = {
            if (args.proxyUser != null) {/*代理用户是否为空*/
              val proxyUser = UserGroupInformation.createProxyUser(args.proxyUser,
                UserGroupInformation.getCurrentUser())
              try {
                proxyUser.doAs(new PrivilegedExceptionAction[Unit]() {
                  override def run(): Unit = {
                    runMain(args, uninitLog)
                  }
                })
              } catch {
                case e: Exception =>
                  if (e.getStackTrace().length == 0) {
                    error(s"ERROR: ${e.getClass().getName()}${e.getMessage()}")
                  } else {
                    throw e
                  }
              }
            } else {
              runMain(args, uninitLog)/*最终调用的方法*/
            }
          }
          if (args.isStandaloneCluster && args.useRest) {/*判断集群部署模式*/
            try {
              logInfo("Running Spark using the REST application submission protocol.")
              doRunMain()/*最终还是调用 doRunMain 在上面*/
            } catch {
              case e: SubmitRestConnectionException =>
                logWarning(s"Master endpoint ${args.master} was not a REST server. " +
                  "Falling back to legacy submission gateway instead.")
                args.useRest = false
                submit(args, false)
            }
          } else {
            doRunMain()/*最终还是调用 doRunMain 在上面*/
          }
        }
       org.apache.spark.deploy.SparkSubmit 893行
        private def runMain(args: SparkSubmitArguments, uninitLog: Boolean): Unit = {
          /*内部是判断集群模式*/
          val (childArgs, childClasspath, sparkConf, childMainClass) = prepareSubmitEnvironment(args)
          if (uninitLog) {
            Logging.uninitialize()
          }

          if (args.verbose) {
            logInfo(s"Main class:\n$childMainClass")
            logInfo(s"Arguments:\n${childArgs.mkString("\n")}")
            logInfo(s"Spark config:\n${Utils.redact(sparkConf.getAll.toMap).mkString("\n")}")
            logInfo(s"Classpath elements:\n${childClasspath.mkString("\n")}")
            logInfo("\n")
          }
          val loader = getSubmitClassLoader(sparkConf)/*获取类加载器*/
          for (jar <- childClasspath) {
            addJarToClasspath(jar, loader)/*上传jar包到classpath*/
          }

          var mainClass: Class[_] = null

          try {
            mainClass = Utils.classForName(childMainClass)/*加载类*/
          } catch {
            ......
          }
          /*类是不是SparkApplication的子类*/
          val app: SparkApplication =
            if (classOf[SparkApplication].isAssignableFrom(mainClass)) {
              mainClass.getConstructor().newInstance().asInstanceOf[SparkApplication]
            } else {
              new JavaMainApplication(mainClass)/*初始化 SparkApplication*/
            }
          ......

          try {
            app.start(childArgs.toArray, sparkConf)/*启动方法 JavaMainApplication 的实现类*/
          } catch {
            case t: Throwable =>
              throw findCause(t)
          } finally {
            if (args.master.startsWith("k8s") && !isShell(args.primaryResource) &&
                !isSqlShell(args.mainClass) && !isThriftServer(args.mainClass)) {
              try {
                SparkContext.getActive.foreach(_.stop())
              } catch {
                case e: Throwable => logError(s"Failed to close SparkContext: $e")
              }
            }
          }
        }
       org.apache.spark.deploy.JavaMainApplication 41行
        override def start(args: Array[String], conf: SparkConf): Unit = {
          val mainMethod = klass.getMethod("main"new Array[String](0).getClass)/*反射机制调用改类的main方法*/
          if (!Modifier.isStatic(mainMethod.getModifiers)) {
            throw new IllegalStateException("The main method in the given main class must be static")
          }

          val sysProps = conf.getAll.toMap
          sysProps.foreach { case (k, v) =>
            sys.props(k) = v
          }

          mainMethod.invoke(null, args)//朴实无华的invoke完成加载
        }
  • 相关阅读:
    android gradle 多渠道打包
    Gradle Plugin User Guide 中文版
    最好的JAVA IDE IntelliJ IDEA使用简介(一)—之界面元素
    ANDROID 中UID与PID的作用与区别
    HTTP Header 详解
    HTTP协议详解
    Volatile总结
    Condition-线程通信更高效的方式
    JAVA基础知识点(转载的)
    CountDownLatch和CyclicBarrier的区别
  • 原文地址:https://www.cnblogs.com/wuxiaolong4/p/16688946.html
Copyright © 2020-2023  润新知