上一节学习了Spark源码的编译方法,这一节我们跟踪一下spark-shell的启动.
spark-shell是spark提供一个控制台,通过它我们可以方便的学习spark的API,类似于Scala的REPL.
spark-shell在/bin目录下,下面简单分析一下spark-shell的启动。
spark-shell———>spark-submit————->spark-class
这是spark-shell启动时依次调用的三个shell脚本文件,最终在spark-class脚本里加载主类并执行。
1.spark-shell脚本主要做的工作是收集spark-submit相关参数,最后调用spark-submit
/bin/spark-submit –class org.apache.spark.repl.Main “${SUBMISSION_OPTS[@]}” spark-shell “${APPLICATION_OPTS[@]}
这是最终执行的命令,可以看到主要是收集submit参数和application参数到SUBMISSION_OPTS和APPLICATION_OPTS里,并传递给spark-submit.
2.spark-submit根据上一个脚本收集到的参数设置一些必要的环境变量,最后调用spark-class
exec “$SPARK_HOME”/bin/spark-class org.apache.spark.deploy.SparkSubmit “${ORIG_ARGS[@]}”
可以看到在spark-shell传递的参数基础上,加上了主类org.apache.spark.deploy.SparkSubmit.这是真正的入口类。
3.spark-class主要是准备JVM环境相关的参数,并最终执行
exec “$RUNNER” -cp “$CLASSPATH” $JAVA_OPTS “$@”
其中RUNNER是${JAVA_HOME}/bin/Java
$CLASSPATH是spark-class收集的必要的CLASSPATH信息,包括设置spark自己的相关classpath。将所有参数展开后实际最终执行的命令是:
/usr/lib/java/jdk1.7.0_15/bin/java-cp/usr/local/spark/src/spark-1.3.1/spark-1.3.1/conf:/usr/local/spark/src/spark-1.3.1/spark-1.3.1/assembly/target/scala-2.10/spark-assembly-1.3.1-hadoop2.4.0.jar:/usr/local/spark/src/spark-1.3.1/spark-1.3.1/lib_managed/jars/datanucleus-core-3.2.10.jar:/usr/local/spark/src/spark-1.3.1/spark-1.3.1/lib_managed/jars/datanucleus-rdbms-3.2.9.jar:/usr/local/spark/src/spark-1.3.1/spark-1.3.1/lib_managed/jars/datanucleus-api-jdo-3.2.6.jar-XX:MaxPermSize=128m -Dscala.usejavacp=true -Xms512m -Xmx512morg.apache.spark.deploy.SparkSubmit –class org.apache.spark.repl.Main spark-shell
可以看到,红色部分是CLASSPATH,绿色部分是JVM配置,紫色部分是最终加载的类和参数。
spark-shell启动分为三个脚本文件,体现了模块化的思想。不同脚本做不同方面的事,这样方便调试测试和修改。
我们在spark-class里稍做修改,在最终执行命令行前,加入以下内容:
export JAVA_OPTS=”-XX:MaxPermSize=128m $OUR_JAVA_OPTS -Dcom.sun.management.jmxremote.port=8300 -Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1″
配置这些信息,是为了使用jvisualvm跟踪调试。
然后启动spark-shell.启动完成后,启动${JAVA_HOME}/bin/jvisualvm,可以看到spark-shell启动的栈。