基于Spark案例,对Spark内核源码在Standalone提交模式的深度剖析 (乾坤大挪移第一层)

自己最近把spark的知识整理了一下,想要比较清晰的解释下他的初步内核源码机制。以方便自己后期查阅。文章中涉及的
1、stage划分算法
2、master资源调度算法
3、task算法(数据优化,数据本地化)

后期我会基于spark2.0版本的源码进行一次剖析,此次只是初步的,如有未尽事宜。请大家多多批评指正,我愿意接受一切意见,只要不是侮辱。啊啊哈。

序言:

基于下面这段初始代码谈执行过程。

def main(args: Array[String]): Unit = {
    val conf= new SparkConf().setAppName("wordCount").setMaster("local")
    val sc=new SparkContext(conf)
    val lines=sc.textFile("E://spark_zzk/spark.txt",3)
    val words=lines.flatMap{line=>line.split(" ")}
    val pairs=words.map{word=>(word,1)}
    val wordCounts=pairs.reduceByKey{_+_}
    wordCounts.foreach(wordCount=>println(wordCount._1+ " 出现了 " + wordCount._2 + " 次数"))
  }

当这段代码打包,提交到集群上去执行的时候,整个的spark内核执行流程讨论:

一、spark内核执行流程剖析

先上图,梳理一下结构,然后对图解说。图里面的1 2 3代表执行顺序。由于图比较大,有需要的读者可以留下你的QQ邮箱,我后期发给你们。我采用局部截图方式展示。
在这里插入图片描述在这里插入图片描述在这里插入图片描述
以下把图上的步骤再度强化解释一下:

  1. 在提交spark应用的机器上。首先启动Application(自己的spark程序)(提交spark应用的机器的Application里面)
  2. Spark-submit(shell)提交----spark-submit这里使用的是Standalone提交模式,其实它会通过反射的方式,创建和构建一个DriverActor进程出来 (提交spark应用的机器)
  3. DriverActor(进程)
    执行我们的application应用程序,也就是我们自己编写的代码。(回想一下,spark应用的初始代码就是先构造SparkConf,再构造SparkContext)(提交spark应用的机器的DriverActor里面)
  4. SparkContext(它在初始化的时候,做的最重要两件事情,就是构造出来DAGScheduler和TaskScheduler)(提交spark应用的机器的SparkContext里面)
  5. DAGScheduler和TaskScheduler启动,TashScheduler它有自己的后台进程,它就会去连接spark集群中的master,发送的是Application的注册请求,去master注册Application (提交spark应用的机器的SparkContext里面的DAGScheduler和TaskScheduler)
  6. master接受到Application注册的请求后,会使用master的调度算法,在spark集群的worker上,为这个Application启动多个Executer(重点:master的调度算法),Master这时通知worker启动Executor (spark集群的master里面)
  7. Worker worker会为Application启动Executor,Executor可以有多个。(spark集群的单台Worker里面)
  8. Executor(进程)Executor启动之后会将自己反向注册到TaskScheuler上去 (spark集群的单台Worker里面的Executor和提交spark的机器上面的TaskScheuler里面)
  9. 所以,TaskScheduler知道它为这个Application服务的Executor有哪些了。注册的Executor可以有很多个,它们都同时像TaskScheduler上面去注册了。 同时,所有的Executor都反向注册到DriverActor上之后,DriverActor结束SparkContext的初始化。会继续执行我们自己编写的代码 (提交spark应用的机器的DriverActor里面)
  10. 此时,Driver这时的执行过程就很重要了。每执行到一个action操作,就会创建一个job(一个application可以有多个action和transformation操作),job会提交给DAGScheduler。(比较关键) (提交spark应用的机器的DAGScheduler里面)
  11. DAGScheduler会将Job划分为多个stage,然后为每个stage创建一个TaskSet,此处涉及到stage划分算法,后期我单独源码讲解。这时,每一个TaskSet都会给到TaskScheduler (提交spark应用的机器的TaskScheduler里面)
  12. TskScheduler会把TaskSet里每一个task提交到Executor上去执行(这里的Executor都是已经之前步骤注册的Executor)。(涉及到Task分配算法) (提交spark应用的机器的TaskScheduler里面和 Spark集群里面的Executor里面)
  13. Executor每接收到一个task,都会用到TaskRunner来封装task,然后从线程池里取出一个线程,去执行这个TskRunner里面的task (Spark集群里面的Executor里面)
  14. Executor里面的TaskRunner线程池启动。 (Spark集群里面的TaskRunner线程池里面)
  15. TaskRunner:将我们编写的代码,也就是要执行的算子以及函数,拷贝,反序列化,然后执行到task (Spark集群里面的TaskRunner线程池里面的TaskRunner)
  16. 这时每个stage分批次作为taskSet提交到Executor里面的TaskRunner里面的ShuffleMap Task和Result Task去执行(只有最后一个stage是ResultTask,其他都是ShuffleMap),每个task针对RDD的一个partition,执行我们定义的算子和函数,以此类推,直到所有操作执行完毕为止。
发布了31 篇原创文章 · 获赞 13 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/laughing1997/article/details/88965650