美文网首页
Spark的部署脚本解读

Spark的部署脚本解读

作者: 一ke大白菜 | 来源:发表于2018-12-26 22:39 被阅读75次

    Apache Spark is a fast and general-purpose cluster computing system.

    以下分析的是Spark2.3.0 版本。

    Submitting Applications

    The spark-submit script in Spark’s bin directory is used to launch applications on a cluster. It can use all of Spark’s supported cluster managers through a uniform interface so you don’t have to configure your application especially for each one.

    Spark's bin目录下的spark-submit脚本用于在集群上启动应用程序。

    spark-submit:

        # 如果不存在SPARK_HOME的环境变量,就执行find-spark-home脚本,这个脚本肯定是设置SPARK_HOME,具体你可以自己去看看
    20 if [ -z "${SPARK_HOME}" ]; then
    21   source "$(dirname "$0")"/find-spark-home
    22 fi
    23
    24 # disable randomized hash for string in Python 3.3+
    25 export PYTHONHASHSEED=0
    26
        # 执行spark-class脚本,并传递了org.apache.spark.deploy.SparkSubmit等一些参数
    27 exec "${SPARK_HOME}"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@"
    

    spark-submit会去检查SPARK_HOME环境变量,并将提交的应用程序和相关类传递给spark-class脚本执行,接下来我们看看spark-class这个脚本。
    这里涉及到一些shell编程的语法,可以一并简单的学习一下。
    source命令:
    通常用法:source filepath 或 . filepath
    功能:使当前shell读入路径为filepath的shell文件并依次执行文件中的所有语句,通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录。例如,当我们修改了/etc/profile文件,并想让它立刻生效,而不用重新登录,就可以使用source命令,如source /etc/profile。
    exec命令:
    exec将并不启动新的shell,而是用要被执行命令替换当前的shell进程,并且将老进程的环境清理掉,而且exec命令后的其它命令将不再执行。

    spark-class:

        # 同样的检查一遍spark_home环境变量
    20 if [ -z "${SPARK_HOME}" ]; then
    21   source "$(dirname "$0")"/find-spark-home
    22 fi
    23
        # 执行load-spark-env.sh脚本,加载spark的配置信息
    24 . "${SPARK_HOME}"/bin/load-spark-env.sh
    25
    26 # 寻找jvm
    27 if [ -n "${JAVA_HOME}" ]; then
    28   RUNNER="${JAVA_HOME}/bin/java"
    29 else
    30   if [ "$(command -v java)" ]; then
    31     RUNNER="java"
    32   else
    33     echo "JAVA_HOME is not set" >&2
    34     exit 1
    35   fi
    36 fi
    37
    38 # 寻找spark的jar包,并将jar赋值给了LAUNCH_CLASSPATH变量
    39 if [ -d "${SPARK_HOME}/jars" ]; then
    40   SPARK_JARS_DIR="${SPARK_HOME}/jars"
    41 else
    42   SPARK_JARS_DIR="${SPARK_HOME}/assembly/target/scala-$SPARK_SCALA_VERSION/jars"
    43 fi
    44
    45 if [ ! -d "$SPARK_JARS_DIR" ] && [ -z "$SPARK_TESTING$SPARK_SQL_TESTING" ]; then
    46   echo "Failed to find Spark jars directory ($SPARK_JARS_DIR)." 1>&2
    47   echo "You need to build Spark with the target \"package\" before running this program." 1>&2
    48   exit 1
    49 else
    50   LAUNCH_CLASSPATH="$SPARK_JARS_DIR/*"
    51 fi
    52
    53 # Spark的默认构建策略是组装一个包含其所有依赖项的jar。
       # 在进行迭代开发时,这可能很麻烦。在本地开发时,可以创建一个包含所有Spark依赖项的程序集jar,然后在进行更改时仅重新打包Spark本身。
    54 if [ -n "$SPARK_PREPEND_CLASSES" ]; then
    55   LAUNCH_CLASSPATH="${SPARK_HOME}/launcher/target/scala-$SPARK_SCALA_VERSION/classes:$LAUNCH_CLASSPATH"
    56 fi
    57
    58 # For tests
    59 if [[ -n "$SPARK_TESTING" ]]; then
    60   unset YARN_CONF_DIR
    61   unset HADOOP_CONF_DIR
    62 fi
    
    70 build_command() {
          # 启动jvm执行${LAUNCH_CLASSPATH}下org.apache.spark.launcher.Main类解析由spark-submit传进来的参数
    71   "$RUNNER" -Xmx128m -cp "$LAUNCH_CLASSPATH" org.apache.spark.launcher.Main "$@"
    72   printf "%d\0" $?
    73 }
    74
    75 # 关闭posix模式,因为它不允许进程替换
    76 set +o posix
        # 将build_command函数的输出循环读入数组
    77 CMD=()
    78 while IFS= read -d '' -r ARG; do
    79   CMD+=("$ARG")
    80 done < <(build_command "$@")
    81
    82 COUNT=${#CMD[@]}
    83 LAST=$((COUNT - 1))
    84 LAUNCHER_EXIT_CODE=${CMD[$LAST]}
    
        # 某些JVM失败会导致错误被打印到stdout(而不是stderr),这导致解析启动器输出的代码变得混乱。
        # 在这些情况下,检查退出代码是否为整数,如果没有,则将其作为特殊错误情况处理。
    89 if ! [[ $LAUNCHER_EXIT_CODE =~ ^[0-9]+$ ]]; then
    90   echo "${CMD[@]}" | head -n-1 1>&2
    91   exit 1
    92 fi
    93
    94 if [ $LAUNCHER_EXIT_CODE != 0 ]; then
    95   exit $LAUNCHER_EXIT_CODE
    96 fi
    97
        # 做了一个切片
    98 CMD=("${CMD[@]:0:$LAST}")
        # 启动执行org.apache.spark.deploy.SparkSubmit类
    99 exec "${CMD[@]}"
    

    spark-class这个脚本是由spark-submit执行的:

    • 第一步:首先会检查SPARK_HOME等环境变量和配置信息;
    • 第二步:接着将寻找spark的二进制源码jars;
    • 第三步:这个时候就会启动org.apache.spark.launcher.Main类解析spark-submit脚本传进来的参数;
    • 第四步:循环将第三步打印的结果循环读入数据CMD
    • 第五步:执行由CMD组成的命令行。
      这里有一些不常见的命令:
      java:
      执行类,-cp <目录和 zip/jar 文件的类搜索路径>
      set:
      可以设置各种shell选项或者列 出shell变量.单个选项设置常用的特性.在某些选项之后-o参数将特殊特性打开.在某些选项之后使用+o参数将关闭某些特性,不带任何参数的set命 令将显示shell的全部变量.除非遇到非法的选项,否则set总是返回ture
      env:
      用来显示当前用户环境变量
      export:
      用来显示和设置当前用户环境变量

    调试CMD的输出

    Running the Examples and Shell

    Example applications are also provided in Python. For example:
    ./bin/spark-submit examples/src/main/python/pi.py 10

    上面的示例程序可以在spark安装目录的example里面找到,下面我在spark-class脚本的98行和99行之间增加一个CMD数组的输出。

    echo "---------CMD start-----------"
    echo "${CMD[@]}"
    echo "---------CMD end------------"
    

    然后提交运行以上示例程序:

    $ ./spark-submit ${SPARK_HOME}/examples/src/main/python/pi.py 10
    ---------CMD start-----------
    /opt/appl/jdk1.8.0_144/bin/java -cp /opt/appl/spark/conf/:/opt/appl/spark/jars/*:/opt/appl/hadoop/etc/hadoop/:/opt/appl/hadoop/share/hadoop/common/lib/*:/opt/appl/hadoop/share/hadoop/common/*:/opt/appl/hadoop/share/hadoop/hdfs/:/opt/appl/hadoop/share/hadoop/hdfs/lib/*:/opt/appl/hadoop/share/hadoop/hdfs/*:/opt/appl/hadoop/share/hadoop/yarn/lib/*:/opt/appl/hadoop/share/hadoop/yarn/*:/opt/appl/hadoop/share/hadoop/mapreduce/lib/*:/opt/appl/hadoop/share/hadoop/mapreduce/*:/opt/appl/hadoop/contrib/capacity-scheduler/*.jar -Xmx5G org.apache.spark.deploy.SparkSubmit /opt/appl/spark/examples/src/main/python/pi.py 10
    ---------CMD end-------------
    

    由打印出来的CMD得出spark-class脚本最后执行的是org.apache.spark.deploy.SparkSubmit这个类,而我们提交的是一个.py文件程序,我们想知道的python解释器和jvm通信的过程还没有找到,下次我们将分析org.apache.spark.deploy.SparkSubmit 这个类。

    相关文章

      网友评论

          本文标题:Spark的部署脚本解读

          本文链接:https://www.haomeiwen.com/subject/fmgclqtx.html