在Spark应用启动时,会初始化SparkContext对象。在SparkContext中,会创建SchedulerBackend、DAGScheduler、TaskScheduler。
首先,在SparkContext类中,会调用SparkContext.createTaskScheduler()方法,这个方法会根据deployMode的不同来初始化SchedulerBackend、DAGScheduler、TaskScheduler。本文主要是描述Standalone模式下的部署,在这个部署模式下,会先定义TaskSchedulerImpl(只是定义,并未初始化),然后初始化SchedulerBackend,Standalone模式下的Scheduler是StandaloneSchedulerBackend。StandaloneSchedulerBackend是一个继承自CoarseGrainedSchedulerBackend的类,它会继承来自父类的DriverEndpoint,并在自己的类中创建StandaloneAppclient,在StandaloneAppclient中定义ClientEndpoint。在初始化SchedulerBackend完成后,会初始化刚刚定义的TaskSchedulerImpl,初始化TaskSchedulerImpl的时候会传入SchedulerBackend的参数。TaskSchedulerImpl的初始化主要是创建一个调度池,分别对应着对任务的FIFO调度和FAIR调度。在StandaloneSchedulerBackend和TaskSchedulerImpl的初始化都完成过后,再初始化DAGScheduler,传入的参数有SparkContext和TaskSchedulerImpl。
在应用程序启动时,ClientEndpoint的tryRegisterAllMaster会尝试遍历所有Master(因为有Standby),并给它们发送RegisterApplication消息;
Master收到RegisterApplication消息后,会记录应用信息并把该应用加入到等待运行应用列表中,注册完成后发送RegisteredApplication给ClientEndpoint,同时调用startExecutorsOnWorkers方法。
ClientEndpoint接收到RegisteredApplication后,会把注册标识registered设置成true,Master注册线程获取状态变化后,完成注册Application进程。
在startExecutorsOnWorkers方法中分配资源运行应用程序时,调用allocateWorkerResourceToExecutors方法在Worker中启动Executor。这个方法中会给Worker发送LaunchExecutor消息。
在Worker中接受到LaunchExecutor消息后,先实例化ExecutorRunner对象,在ExecutorRunner启动中会创建进程生成器ProcessBuilder,然后由该生成器使用command(在StandaloneSchedulerBackend中定义好的org.apache.spark.executor.CoarseGrainedExecutorBackend)创建CoarseGrainedExecutorBackend对象,该对象是Executor运行的容器,最后Worker发送ExecutorStateChanged消息给Master,通知Executor容器已经创建完毕。在ExecutorRunner启动过程中会调用fetchAndRunExecutor方法进行实现,在该方法中指定构造的Executor为CoarseGrainedExecutorBackend。
Master收到ExecutorStateChanged后,会向ClientEndpoint发送ExecutorUpdated消息, ClientEndpoint会监听这个Executor,如果该Executor处于Finished状态(不是Task处于Finished状态),则触发回收Executor。
在CoarseGrainedExecutorBackend启动方法onStart中,会发送注册RegisterExecutor给DriverEndpoint。DriverEndpoint收到消息后,会先判断该Executor是否已经被注册,如果已注册则发送注册失败RegisterExecutorFailed消息,否则Driver会记录该Executor的消息,并发送RegisteredExecutor消息,在makeOffer方法中分配运行任务资源,最后发送LaunchTask执行任务。
在CoarseGrainedExecutorBackend成功注册后,会实例化Executor对象,Executor对象会跟Driver有心跳通信,等待Driver下发任务。在CoarseGrainedExecutorBackend等到LaunchTask消息后,会调用Executor的launchTask方法,这个方法中,会创建TaskRunner进程,然后把该进程加入到进程调度池threadPool中。
……
TaskRunner如何执行任务以后再讲…
……
在TaskRunner执行任务完成时,会向DriverEndpoint发送StatusUpdate消息,当DriverEndpoint终端点接收到该消息时,调用TaskSchedulerImpl的statusUpdate方法,根据任务执行不同的结果进行处理,处理完毕后再给Executor分配执行任务。