废话:
因为前几天比较了idea和eclipse感觉查询上idea好用,想试试idea,但是用它挖了几天源码后。idea不熟练,挖代码苦不堪言,再度回到eclipse中。
**前言:**上篇已经讲解过spark1.6版本中资源调度的源码,standalone-cluster模式如何实现。今天再扒一扒spark中任务调度的实现。大家都知道,大数据中,计算向数据移动,我个人理解的其实就是计算向资源移动,那么spark中是如何将你提交的app计算任务,分配到集群中各个计算节点中的呢?
逻辑实现分析:我们以client模式讲解下(cluster类同,只不过是将启动driver的方式交给了master,master再去找一台资源充足的启动driver,上篇说过),client提交一个app的任务给driver,当代码中执行action算子之后,driver中会根据DAGScheduler执行action算子,根绝app划分宽窄依赖,然后形成DAG,生成很多stage,每一个stage包含一组task;taskschduler遍历task集合集合,发送task任务到worker节点上的的exeutor上执行。
一、寻找程序入口
1。我们以图中伪代码为例,寻找action算子,找到触发driver的入口。我们找到RDD这个类中foreach算子的位置。
2。 点击跟踪sc.runJob,追踪n多runJob
3.找到这里,我们可以看到,仍然在SparkcContext这个类中,dagScheduler开始划分宽窄依赖
4。点击dagScheduler.runJob,找到核心方法submitJob
二、Job分析(这里比较绕)
1.这里用eventProcessLoop.post方法,传了一个JObsubmit的方法。
2。点进post方法,可以看到,把submit的方法放到了队列里面。
这个queue是一个BlockingQueue
3.但是在哪里真正启动这个线程呢?我们返回上面的eventProcessLoop.post 方法,点击eventProcessLoop,找到他的定义。
4。点击DAGSchedulerEventProcessLoop 查看下这是个什么鬼
我们可以看到这个类继承了EventLoop,点击eventProcessLoop.start()同时看到了这个方法上面启动了二.2中我们讲到的启动了我们的线程
5。往上翻,看下是哪个方法执行了eventProcessLoop.start(),可以看到是DAGScheduler这个类
6.因此,我们上面是分析到,我们通过SparkContext的runJob方法-> dagScheduler.runJob->DAGScheduler的runJob中submitJob方法->eventProcessLoop.post方法将JobSubmitted(
jobId, rdd, func2, partitions.toArray, callSite, waiter,
SerializationUtils.clone(properties))这个函数放到一个名字为eventQueue队列中,但是这个队列的消费端,在DAGScheduler这个类中。因此我们下一步需要找打的创建DAGScheduler类的入口。
在我们编写代码时,我们需要创建SparkContext,通过这个类来生产RDD,SparkContext是spark的唯一通道,因此很可能在执行SparkContext 时候就已经创建好了。经过查找,果然是这样的。
因此我们猜想,其实driver在代码执行创建SparkContext的时候就已经创建好了。
7.上面我们已经找到消费eventQueue的地方了,接下来找下,这个被消费的eventQueue里,做了什么处理。
8。点击doOnReceive
9.我们上面传的方法是JobSubmitted 方法,因此我们点击dagScheduler.handleJobSubmitted 看下
我们看到有finalRDD,finalStage,说明,这个方法是划分宽窄依赖,划分stage的核心。也就是DAGScheduler的核心,stage的划分是通过我们计算流程的最后一个rdd来进行划分的。
我们以下图RDD与stage的划分跟踪这段代码
10.点击submitStage,其中finalStage中封装只有最后一个RDD,如下图我们可以看到submitStage这是个递归方法,
11.点击getMissingParentStages 方法,通过封装最后一个rdd的最后一个stage,向前推导,寻找父stage。
visit是匿名函数,waitingForVisit把最后一个stage放来了,第一轮循环执行步骤如下图
第二轮循环,
因此最后missing里存逻辑上放了两个宽依赖G-_F,B-A
12。我们回到submitStage 方法,轮询missing中的F和A,直到最后misssing为空,F和A轮询中执行submitMissingTasks,
13.点击submitMissingTasks 方法,往下看就会看到taskScheduler.submitTasks 方法。我们可以看到
传的是一组task集合
三、task发送
1。点击submitTasks 方法找到实现类。
2。我们看到最后执行 backend.reviveOffers() 我们看下backend是啥
3。找SchedulerBackend 的继承类CoarseGrainedSchedulerBackend,查找上面的reviveOffers 方法。
如上图,可以看到又发消息了。。
4.看下ReviveOffers是谁,如下图它继承了CoarseGrainedClusterMessage ,点进来发现没有任何用,哈哈。
5.然后看下CoarseGrainedSchedulerBackend 在哪里用了它。
在这里case了一下
6.点击makeOffers,点击launchTasks
7。如下图解析,已经向executor发送task了
四、task任务执行
1.我们需要找到executor类去找到接收task的方法大。