上次我们已经说完了 Spark Standalone 的 Master 和 Worker 的启动流程,本次我们从一个提交 Spark 作业的命令开始阅读 Spark 任务提交的源码。
在 Spark 客户端提交任务的流程是这样子的:
./bin/spark-submit --class org.apache.spark.examples.SparkPi \
--master local \
--deploy-mode cluster \
--driver-memory 4g \
--executor-memory 2g \
--executor-cores 1 \
lib/spark-examples*.jar \
10
spark-submit 脚本里面,最终是执行这样一句:
exec "${SPARK_HOME}"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@"
执行的是 SparkSubmit 这个类的 main 方法,传入进去了一系列的参数。
main 方法中,没有什么逻辑,继续点到最终的执行逻辑的地方
然后到 runMain 方法中,第一句代码就非常重要:准备提交的环境,主要是从参数中,解析出执行的主类,childMainClass
点进去,重点看 childMainClass 赋值的地方:如果是 standalone 模式,不是 restful 的形式,则主类是:org.apache.spark.deploy.ClientApp
如果是 yarn-cluster 模式,则主类是:org.apache.spark.deploy.yarn.YarnClusterApplication
然后下面还有对提交到 mesos 和 k8s 的情况,这里就不看了。
有了主类之后,使用反射的方式,初始化一个实例:
并且调用这个类的 start 方法:
这里我们只看 Spark Standalone 模式,主类是 ClientApp 的情况。
看一下 ClientApp 的 start 方法,初始化了 RpcEnv,并且注册了一个 Endpoint,那么下面就肯定要看 ClientEndpoint 的 onStart() 方法了。
在当前类中搜索 onStart() 方法:
在 onStart() 方法中,有个东西很重要:
这个 DriverWrapper ,这个是启动 Driver 的主类。
!!注意,当前我们还不是在 Driver 里面,我们只是在客户端上启动了一个 JVM,里面执行了 SparkSubmit 的 main 方法,初始化了一个 ClientEndpoint,这个 ClientEndpoint 等会要发送一个消息给 Master,让 Master 找一台机器,启动 Driver 进程。
然后,把 mainClass 封装到了 Command 中:
并且初始化了一个 DriverDescription:
接下来,把 DriverDescription 作为参数放到 RequestSubmitDriver 消息中,把这个消息发给 Master ,向 Master 注册 Driver:
今天主要阅读了提交的一点源码,当执行 spark-submit 脚本时,客户端会启动一个 JVM,注册 ClientEndpoint,向 Master 发送 注册 Driver 的消息:RequestSubmitDriver
下次继续分析 Master 收到消息之后,是如何处理这个消息的