很多人在使用Spark做计算时,都会对SparkSubmit Job之后执行流程比较模糊,尤其在Spark2.0之后正式使用Netty作为RPC通讯框架,在源码层对许多功能进行了抽象,这对一些Spark初学者来说,阅读源码是一件比较困难的事。不过笔者认为,虽然Spark2.0之后框架对功能层面做了很多的抽象工作,但其执行流程还没有什么改变。虽然笔者在工作已经使用了Spark2.2.1作为生产发行版本,但从代码阅读的角度来说,笔者依然推荐Spark1.3.1版本,这个版本下的源码还是比较容易阅读的。
本文将从执行Spark-Submit --jar 之后开展其流程梳理:
- 在脚本中spark-submit --jar 后,代码首先会进入SparkSubmit类的main()方法,main()方法中调用了runMain()
- runMain()中通过mainMethod.invoke(null, childArgs.toArray)反射的方法在同一线程内执行WordCount类中的main()方法
- WordCount类中的main()方法会对SparkContext进行new的实例化
- 实例化SparkContext后,SparkContext首先会对调用createSparkEnv()实例化SparkEnv
- SparkEnv中调用了自身的create()方法实现单例模式
- create()方法用调用了AkkaUtils.createActorSystem()创建了一个Akka的一个ActorSystem实例
- createActorSystem()方法中调用了自身方法doCreateActorSystem()返回一个ActorSystem实例
- doCreateActorSystem()方法中使用ActorSystem的Apply()方法返回实例
- createActorSystem()方法中调用了Utils.startServiceOnPort()启动ActorSystem
- SparkContext后续调用了createTaskScheduler()方法实例化了TaskScheduler,以及new了一个DAGSheduler实例
- 最后调用TaskScheduler.start()启动任务