当我们编写完Spark应用后,在机器上提交它时,是通过编写shell脚本,其中有个命令是spark-submit,提交后程序会通过某种运行模式来在集群中运行目前接触到的为Standalone模式,这种模式会通过反射的方式,创建一个Driver进程出来。
Driver进程会执行我们编写的Spark代码,每次编写代码时首先要构造SparkConf和SparkContext,SparkContext在初始化时会构造出两个重要的调度器——DAGScheduler和TaskScheduler。TaskScheduler会通过一个后台进程去和Master节点进行通信,在Master上注册Application。Master接收到注册请求后会使用自己的资源调度算法,在Worker节点上为该应用启动多个Executor进程。
Executor启动之后会自己反向注册到TaskScheduler上,当反向注册结束后,SparkContext初始化完成,继续向下执行代码。每次执行到一个action操作,就会创建一个job提交给DAGScheduler,DAGScheduler会将job划分为多个stage,然后通过划分算法为每一个stage创建一个TaskSet。TaskScheduler负责管理TaskSet,它会根据task分配算法将TaskSet里的每一个task提交到Executor上执行。Executor每接受一个task都会使用TaskRunner来封装task,然后从线程池中取出一个线程执行这个task。
TaskRunner:将代码拷贝反序列化然后执行task。
task有两种,ShuffleMapTask和ResultTask,只有最后一个stage是ResultTask之前的stage都是ShuffleMapTask。整个Spark应用程序的执行就是stage分批次作为taskset提交到executor执行,每个task针对RDD的一个partition,执行我们定义的算子和函数。
加粗的三个算法都是非常重要的,后面会详细讲解。