Spark核心源码(一):spark-submit

1.Spark 源码相关目录介绍

spark 源码下载地址:https://github.com/apache/spark 选择自己需要阅读的分支(github网速慢可以到我这里下:https://gitee.com/zsmas10/sparksource),目前spark 版本已经到3.0.0,因为目前线上使用的主要版本为2.4, 所以当前阅读源码还是以2.4 为主。 下图为整个spark源码的目录结构:
spark
bin 目录下存放的spark运行shell 相关的脚本,包括pyspark,sprkR,spark-shell,spark-sql等脚本。通过其中一个pyspark脚本分析,如何启动这些脚本的。

  1. 查看pyspark脚本,pyspark最后通过 spark-submit pyspark-shell-main --name “PySparkShell” “$@”
  2. 跟踪spark-submit脚本分析,spark-submit 最终调用 spark-class org.apache.spark.deploy.SparkSubmit “$@”
  3. 跟踪spark-class 文件,关键代码 R U N N E R " − X m x 128 m − c p " RUNNER" -Xmx128m -cp " RUNNER"Xmx128mcp"LAUNCH_CLASSPATH” org.apache.spark.launcher.Main “$@” 其中RUNNER 调用java的命令, LAUNCH_CLASSPATH 为基础jar包
  4. 可以查看到最终调用的 org.apache.spark.launcher.Main 关键类,后续分析该类

接下来,简单介绍下几个主要的目录:

  • core 目录下存放的spark的核心代码,java 和 scala两部分代码组成,核心模块
  • data 目录下存放一些文本数据文件,用于mllib、graphx、streaming等模块测试用。
  • mllib 机器学习相关模块代码
  • R sparkR核心代码
  • python pyspark 核心代码
  • sql sparkSQL 核心代码
  • streaming spark_streaming 核心代码
  • sbin spark集群启动相关命令

2.Spark 集群启动相关脚本

主要开一下sbin 目录下start-master.sh脚本,该脚本主要启动spark集群中master角色。查看该启动脚本,其中关键性代码

"${SPARK_HOME}/sbin" /spark-daemon.sh start $CLASS 1 \
  --host $SPARK_MASTER_HOST --port $SPARK_MASTER_PORT --webui-port $SPARK_MASTER_WEBUI_PORT \
  $ORIGINAL_ARGS

其中 $CLASS 为 org.apache.spark.deploy.master.Master 该类存在于spark-core 模块下。分析core下的包org.apache.spark.deploy.master.Master,Master类中查看main 方法

def main(argStrings: Array[String]) {
    Thread.setDefaultUncaughtExceptionHandler(new 
        SparkUncaughtExceptionHandler(    exitOnUncaughtException = false))  
    Utils.initDaemon(log)  
    val conf = new SparkConf  
    val args = new MasterArguments(argStrings, conf)  
    val (rpcEnv, _, _) = startRpcEnvAndEndpoint(args.host,args.port, args.webUiPort, conf)  rpcEnv.awaitTermination()}

Main 方法中主要有startRpcEnvAndEndpoint 方法,该方法主要创建 Master的 RPC环境。
首先看一下new SparkConf Master 启动的配置信息,会读取以 spark. 开头的系统属性,作为启动的参数。
而MasterArguments 很明显即为Master 启动创建的参数配置。
重点关注 RPC 环境的创建过程,因为SPARK_RPC通信环境,在Netty上封装了一层,以RpcEndpoint 为基础,会在后面单独介绍。

/** 
 * Start the Master and return a three tuple of: 
 *   (1) The Master RpcEnv   master rpc 环境
 *   (2) The web UI bound port  master的 web ui 端口
 *   (3) The REST server bound port, if any  
*/
def startRpcEnvAndEndpoint(    
    host: String,    
    port: Int,    
    webUiPort: Int,    
    conf: SparkConf): (RpcEnv, Int, Option[Int]) = {  
val securityMgr = new SecurityManager(conf)  
val rpcEnv = RpcEnv.create(SYSTEM_NAME, host, port, conf, securityMgr)  
val masterEndpoint = rpcEnv.setupEndpoint(ENDPOINT_NAME,    
    new Master(rpcEnv, rpcEnv.address, webUiPort, securityMgr, conf))  
val portsResponse =  masterEndpoint.askSync[BoundPortsResponse](BoundPortsRequest)  
// 返回三个值
(rpcEnv, portsResponse.webUIPort, portsResponse.restPort)}

在该方法中,创建一个rpc通信环境,传入参数 host,port 等参数,通过 RpcEnvFactory 工厂类创建,由于在在spark2.4 版本中,rpc通信中主要使用netty框架,因此RPC创建主要由 NettyRpcEnvFactory 实现,具体RPC通信如何实现,在后面的文档中说明。 在startRpcEnvAndEndpoint 方法中返回三个值,masterRpc rpcEndpoint用于和slave进行交互, webUI 及 portsResponse.restPort 。 最后在main方法中执行rpcEnv.awaitTermination() 开启守护进程,一直等待。
整个Master的启动流程图,如下:在这里插入图片描述

3.slave 启动脚本分析

查看start-slave.sh 与start-master.sh 类似,主要是通过spark-daemon.sh 脚本,

"${SPARK_HOME}/sbin"/spark-daemon.sh start $CLASS $WORKER_NUM \
     --webui-port "$WEBUI_PORT" $PORT_FLAG $PORT_NUM $MASTER "$@"

slave 启动主要启用 org.apache.spark.deploy.worker.Worker 类,查看Worker 启动和Master 启动类似。

4.spark-daemon 分析

在 Master 和 Slave 启动的脚本中,有一个重要的脚本spark-daemon.sh, 启动过程中,都是调用 spark-daemon.sh start 启动对应的Master 和 Worker 类.

4.1 spark-daemon.sh脚本

spark-daemon 通过脚本名称可以知道该脚本Run a Spark command as a daemon 其中核心命令

case $option in

 (submit)
   run_command submit "$@"
   ;;

 (start)
   run_command class "$@"
   ;;

Master与Slave启动过程中,都是调用daemon start命令,可以看到脚本命令中,case "$mode"的选择。

case "$mode" in
   (class)
     execute_command nice -n "$SPARK_NICENESS" "${SPARK_HOME}"/bin/spark-class "$command" "$@"
     ;;

   (submit)
     execute_command nice -n "$SPARK_NICENESS" bash "${SPARK_HOME}"/bin/spark-submit --class "$command" "$@"
     ;;

   (*)
     echo "unknown mode: $mode"
     exit 1
     ;;
 esac

根据mode判断是调用spark-class还是调用spark-submit命令,由于在启动集群脚本中,基本都是class命令,所以调用spark-class文件

4.2 spark-class 脚本

观察上述命令,其中调用/bin/spark-class 脚本,运行相关的启动类。 在 /bin/spark-class 脚本中主要有两个部分

build_command() {
  "$RUNNER" -Xmx128m -cp "$LAUNCH_CLASSPATH" org.apache.spark.launcher.Main "$@"
  printf "%d\0" $?
}

通过build_command 生成了要执行的shell命令; launcher模块中的 org.apache.spark.launcher.Main 下

if (className.equals("org.apache.spark.deploy.SparkSubmit")) {
      try {
        builder = new SparkSubmitCommandBuilder(args);
      } catch (IllegalArgumentException e) {
        printLaunchCommand = false;
        System.err.println("Error: " + e.getMessage());
        System.err.println();

        MainClassOptionParser parser = new MainClassOptionParser();
        try {
          parser.parse(args);
        } catch (Exception ignored) {
          // Ignore parsing exceptions.
        }

        List<String> help = new ArrayList<>();
        if (parser.className != null) {
          help.add(parser.CLASS);
          help.add(parser.className);
        }
        help.add(parser.USAGE_ERROR);
        builder = new SparkSubmitCommandBuilder(help);
      }
    } else {
      builder = new SparkClassCommandBuilder(className, args);
    }
}

看出sparkSubmit 和其它的命令都是在这里生成具体的SparkClassComand,仔细跟踪代码,会调用一个SparkClassCommandBuilder的class中的buildCommand方法
在这里插入图片描述
这里会根据不同的类生成具体的java执行方法。 在class类中完成了命令的组装之后;回到spark-class脚本中,通过 exec “${CMD[@]}” 启动进程执行org.apache.spark.launcher.Main返回的命令 可以看到Master启动脚本

 "$sbin"/spark-daemon.sh start org.apache.spark.deploy.master.Master 1 \
    --ip $SPARK_MASTER_IP --port $SPARK_MASTER_PORT \
    --webui-port $SPARK_MASTER_WEBUI_PORT

这样就执行调用Master类的main方法,开启了Master的启动过程,整个Master的启动过程还算是比较清晰,在Master中还有一个关键方法 onStart()
在这里插入图片描述
看一下OnStart()这个方法,Master启动的逻辑在这个里面实现,但是onStart() 方法在什么时候调用,这个一直没有出现。同时在Master的main方法中也没有调用记录,那这个方法如何启动的?后面会研究分析Master启动与RPC通信。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spark submit任务提交是指将用户编写的Spark应用程序提交到集群中运行的过程。在Spark中,用户可以通过命令行工具或API方式提交任务。 Spark submit命令的基本语法如下: ``` ./bin/spark-submit \ --class <main-class> \ --master <master-url> \ --deploy-mode <deploy-mode> \ --conf <key>=<value> \ <application-jar> \ [application-arguments] ``` 其中,`--class`指定应用程序的主类,`--master`指定集群的URL,`--deploy-mode`指定应用程序的部署模式,`--conf`指定应用程序的配置参数,`<application-jar>`指定应用程序的jar包路径,`[application-arguments]`指定应用程序的命令行参数。 在Spark中,任务提交的过程主要包括以下几个步骤: 1. 创建SparkConf对象,设置应用程序的配置参数; 2. 创建SparkContext对象,连接到集群; 3. 加载应用程序的主类; 4. 运行应用程序的main方法; 5. 关闭SparkContext对象,释放资源。 在任务提交的过程中,Spark会自动将应用程序的jar包和依赖的库文件上传到集群中,并在集群中启动Executor进程来执行任务。任务执行完成后,Spark会将结果返回给Driver进程,并将Executor进程关闭。 总之,Spark submit任务提交是Spark应用程序运行的关键步骤,掌握任务提交的原理和方法对于开发和调试Spark应用程序非常重要。 ### 回答2: Spark 作为一款强大的分布式计算框架,提供了很多提交任务的方式,其中最常用的方法就是通过 spark-submit 命令来提交任务。spark-submitSpark 提供的一个命令行工具,用于在集群上提交 Spark 应用程序,并在集群上运行。 spark-submit 命令的语法如下: ``` ./bin/spark-submit [options] <app jar | python file> [app arguments] ``` 其中,[options] 为可选的参数,包括了执行模式、执行资源等等,<app jar | python file> 为提交的应用程序的文件路径,[app arguments] 为应用程序运行时的参数。 spark-submit 命令会将应用程序的 jar 文件以及所有的依赖打包成一个 zip 文件,然后将 zip 文件提交到集群上运行。在运行时,Spark 会根据指定的主类(或者 Python 脚本文件)启动应用程序。 在提交任务时,可以通过设置一些参数来控制提交任务的方式。例如: ``` --master:指定该任务运行的模式,默认为 local 模式,可设置为 Spark Standalone、YARN、Mesos、Kubernetes 等模式。 --deploy-mode:指定该任务的部署模式,默认为 client,表示该应用程序会在提交任务的机器上运行,可设置为 cluster,表示该应用程序会在集群中一台节点上运行。 --num-executors:指定该任务需要的 executor 数量,每个 executor 会占用一个计算节点,因此需要根据集群配置与任务要求确定该参数的值。 --executor-memory:指定每个 executor 可用的内存量,默认为 1g,可以适当调整该值以达到更好的任务运行效果。 ``` 此外,还有一些参数可以用来指定应用程序运行时需要传递的参数: ``` --conf:指定应用程序运行时需要的一些配置参数,比如 input 文件路径等。 --class:指定要运行的类名或 Python 脚本文件名。 --jars:指定需要使用的 Jar 包文件路径。 --py-files:指定要打包的 python 脚本,通常用于将依赖的 python 包打包成 zip 文件上传。 ``` 总之,spark-submitSpark 提交任务最常用的方法之一,通过该命令能够方便地将应用程序提交到集群上运行。在提交任务时,需要根据实际场景调整一些参数,以达到更好的任务运行效果。 ### 回答3: Spark是一个高效的分布式计算框架,其中比较重要的组成部分就是任务提交。在Spark中,任务提交主要通过spark-submit来实现。本文将从两方面,即任务提交之前的准备工作和任务提交过程中的细节进行探讨。 一、任务提交之前的准备工作 1.环境配置 在执行任务提交前,需要确保所在的计算机环境已经配置好了SparkSpark的环境配置主要包括JAVA环境、Spark的二进制包、PATH路径配置、SPARK_HOME环境变量配置等。 2.编写代码 Spark的任务提交是基于代码的,因此在任务提交前,需要编写好自己的代码,并上传到集群中的某个路径下,以便后续提交任务时调用。 3.参数设置 在任务提交时,需要对一些关键的参数进行设置。例如,任务名、任务对应的代码路径、任务需要的资源、任务需要的worker节点等。 二、任务提交过程中的细节 1.启动Driver 当使用spark-submit命令提交任务时,Spark会启动一个Driver来运行用户的代码。这个Driver通常需要连接到Spark集群来执行任务。 2.上传文件 Spark支持在任务提交时上传所需的文件。这些文件可以用于设置Spark的环境变量、为任务提供数据源等。 3.资源需求 Spark的任务执行依赖于一定的资源。每个任务可以指定自己的资源需求,例如需要多少内存、需要多少CPU等。这些资源需求通常与提交任务时需要的worker节点数量有关系。 4.监控和日志 在任务执行的过程中,Spark会收集任务的监控数据和日志信息。这些数据可用于后续的调试和性能优化。 总之,在Spark任务提交过程中,需要充分考虑任务的资源需求和监控日志信息的收集,以便更好地完成任务和优化Spark运行效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值