内核架构剖析
问题导读:
- Spark的架构是什么?各组件的功能是什么?各组件之间的关系是什么?
- Spark作业提交流程是怎么样的?
Spark Standalone模式是spark很常见的一种模式,集群角色分为Driver,Worker,Master三个端。
- Driver端是指提交spark-submit的服务器,主要会将提交的程序分为多个的task,交由worker端执行。
- Master端是集群的大脑,负责协调,分配资源给worker。
- Worker端是集群“办事的人”,主要接受Master的调度,以及driver端传来的task的执行。
使用Standalone方式提交。
object WordCount {
def main(args: Array[String]): Unit = {
// 1.创建SparkConf对象
val conf=new SparkConf();
// 2.创建SparkContext对象
val sc=new SparkContext(conf)
// 3.读取数据
val line = sc.textFile("...")
// 4.逻辑处理
val wordsRDD = line.flatMap(_.split(" "))
val pairs = wordsRDD.map(word => (word,1))
val wordcounts = pairs.reduceByKey(_+_)
wordcounts.collect().foreach(wordNum=>println(wordNum._1+":"+wordNum._2))
sc.stop()
}
}
以wordCount
为例,将编写好的代码打成jar包,通过spark-submit
方式提交到spark
某节点上,会通过反射的方式,创建构造一个DriverActor
进程,就是经常说的Driver
,进而执行代码。以下为具体流程:
- 提交一个job,启动一个Drive进程。Driver进程会先构造SparkConf,再构造SparkContext,这个和编写的初始化代码顺序一致;
- 在SparkContext初始化时,会先构造出来DAGScheduler和TaskScheduler。DAGScheduler负责创建job,Application在遇到action操作时,才会真正的提交任务并进行计算。这时Spark会根据action操作之前的Transform操作的关联关系,生成一个DAG,将DAG中的RDD划分到不同的stage,提交stage等。TaskScheduler负责用调度算法,对集群管理器已经分配给应用程序的资源进行二次调度后,分配给任务。TaskScheduler调度的Task是由DAGScheduler创建的,所以DAGScheduler是TaskScheduler的前置调度。
- TaskScheduler在初始化时,通过对应的后台进程,连接Master,向Master注册Application
- Master接收到Application注册的请求后,会使用自己的资源调度算法,在Spark集群的Worker上,为这个Application启动多个execution
- worker会为application启动executor进程。executor启动之后会反向注册到TaskScheduler
- 每执行一个action就会创建一个job,提交给DAGScheduler。DAGScheduler会将job划分为多个stage(stage划分算法),然后每个stage创建一个taskSet。taskScheduler会把taskSet里每个task提交到executor(分配算法)
- executor每接收到一个task都会用taskRunner来封装task,然后从线程池中取出一个线程,执行这个task。
- taskRunner将代码中的算子和函数拷贝、反序列化,然后执行task。
- task有两种,一中是shufflemapTask和resulttask,只有最后一个task是resulttask,其余都是shuffleMapTask
- 最后整个spark应用程序的执行就是stage分批次作为taskset提交到executor执行,每个task针对rdd的一个partiiton,执行我们定义的算子和函数。
一级调度:给application分配并运行executor
二级调度:给任务分配executor并运行任务
不论Spark以何种模式进行部署,任务提交后,都会先启动Driver进程,随后Driver进程向集群管理器注册应用程序,之后集群管理器根据此任务的配置文件分配Executor并启动,当Driver所需的资源全部满足后,Driver开始执行main函数,Spark查询为懒执行,当执行到action算子时开始反向推算,根据宽依赖进行stage的划分,随后每一个stage对应一个taskset,taskset中有多个task,根据本地化原则,task会被分发到指定的Executor去执行,在任务执行的过程中,Executor也会不断与Driver进行通信,报告任务运行情况。
参考资料:
【Spark 内核】Spark 内核解析-上
Spark Scheduler模块详解-DAGScheduler实现