【Spark2.0源码学习】-10.Task执行与回馈


- ExecutorEndpoint接受到LaunchTask指令后,解码出TaskDescription,调用Executor的launchTask方法
- Executor创建一个TaskRunner线程,并启动线程,同时将改线程添加到Executor的成员对象中,代码如下:
private val runningTasks = new ConcurrentHashMap[Long, TaskRunner]
runningTasks.put(taskDescription.taskId, taskRunner)
- TaskRunner
- 首先向DriverEndpoint发送任务最新状态为RUNNING
- 从TaskDescription解析出Task,并调用Task的run方法
 
- Task
- 创建TaskContext以及CallerContext(与HDFS交互的上下文对象)
- 执行Task的runTask方法
- 如果Task实例为ShuffleMapTask:解析出RDD以及ShuffleDependency信息,调用RDD的compute()方法将结果写Writer中(Writer这里不介绍,可以作为黑盒理解,比如写入一个文件中),返回MapStatus对象
- 如果Task实例为ResultTask:解析出RDD以及合并函数信息,调用函数将调用后的结果返回
 
 
- TaskRunner将Task执行的结果序列化,再次向DriverEndpoint发送任务最新状态为FINISHED


- DriverEndpoint接受到StatusUpdate消息后,调用TaskScheduler的statusUpdate(taskId, state, result)方法
- TaskScheduler如果任务结果是完成,那么清除该任务处理中的状态,并调动TaskResultGetter相关方法,关键代码如下:
val taskSet = taskIdToTaskSetManager.get(tid) taskIdToTaskSetManager.remove(tid)
taskIdToExecutorId.remove(tid).foreach { executorId =>
executorIdToRunningTaskIds.get(executorId).foreach { _.remove(tid) }
}
taskSet.removeRunningTask(tid) if (state == TaskState.FINISHED) {
taskResultGetter.enqueueSuccessfulTask(taskSet, tid, serializedData)
} else if (Set(TaskState.FAILED, TaskState.KILLED, TaskState.LOST).contains(state)) {
taskResultGetter.enqueueFailedTask(taskSet, tid, state, serializedData)
}
- TaskResultGetter启动线程启动线程【task-result-getter】进行相关处理
- 通过解析或者远程获取得到Task的TaskResult对象
- 调用TaskSet的handleSuccessfulTask方法,TaskSet的handleSuccessfulTask方法直接调用TaskSetManager的handleSuccessfulTask方法
 
- TaskSetManager
- 更新内部TaskInfo对象状态,并将该Task从运行中Task的集合删除,代码如下:
 
val info = taskInfos(tid)
info.markFinished(TaskState.FINISHED, clock.getTimeMillis())
removeRunningTask(tid)
- 调用DAGScheduler的taskEnded方法,关键代码如下:
 
sched.dagScheduler.taskEnded(tasks(index), Success, result.value(), result.accumUpdates, info)
- DAGScheduler向DAGSchedulerEventProcessLoop存入CompletionEvent指令,CompletionEvent对象定义如下
private[scheduler] case class CompletionEvent(
task: Task[_],
reason: TaskEndReason,
result: Any,
accumUpdates: Seq[AccumulatorV2[_, _]],
taskInfo: TaskInfo)
extends DAGSchedulerEvent


- DAGSchedulerEventProcessLoop接收到CompletionEvent指令后,调用DAGScheduler的handleTaskCompletion方法
- DAGScheduler根据Task的类型分别处理
- 如果Task为ShuffleMapTask
- 待回馈的Partitions减取当前partitionId
- 如果所有task都返回,则markStageAsFinished(shuffleStage),同时向MapOutputTrackerMaster注册MapOutputs信息,且markMapStageJobAsFinished
- 调用submitWaitingChildStages(shuffleStage)进行下层Stages的处理,从而迭代处理最终处理到ResultTask,job结束,关键代码如下:
 
private def submitWaitingChildStages(parent: Stage) {
   ...
  val childStages = waitingStages.filter(_.parents.contains(parent)).toArray
  waitingStages --= childStages
  for (stage <- childStages.sortBy(_.firstJobId)) {
    submitStage(stage)
  }
}
- 如果Task为ResultTask
- 改job的partitions都已返回,则markStageAsFinished(resultStage),并cleanupStateForJobAndIndependentStages(job),关键代码如下
 
for (stage <- stageIdToStage.get(stageId)) {
  if (runningStages.contains(stage)) {
    logDebug("Removing running stage %d".format(stageId))
    runningStages -= stage
  }
  for ((k, v) <- shuffleIdToMapStage.find(_._2 == stage)) {
    shuffleIdToMapStage.remove(k)
  }
  if (waitingStages.contains(stage)) {
    logDebug("Removing stage %d from waiting set.".format(stageId))
    waitingStages -= stage
  }
  if (failedStages.contains(stage)) {
    logDebug("Removing stage %d from failed set.".format(stageId))
    failedStages -= stage
  }
}
// data structures based on StageId
stageIdToStage -= stageId
jobIdToStageIds -= job.jobId
jobIdToActiveJob -= job.jobId
activeJobs -= job
【Spark2.0源码学习】-10.Task执行与回馈的更多相关文章
- 【Spark2.0源码学习】-1.概述
		Spark作为当前主流的分布式计算框架,其高效性.通用性.易用性使其得到广泛的关注,本系列博客不会介绍其原理.安装与使用相关知识,将会从源码角度进行深度分析,理解其背后的设计精髓,以便后续 ... 
- spark2.0源码学习
		[Spark2.0源码学习]-1.概述 [Spark2.0源码学习]-2.一切从脚本说起 [Spark2.0源码学习]-3.Endpoint模型介绍 [Spark2.0源码学习]-4.Master启动 ... 
- 【Spark2.0源码学习】-2.一切从脚本说起
		从脚本说起 在看源码之前,我们一般会看相关脚本了解其初始化信息以及Bootstrap类,Spark也不例外,而Spark我们启动三端使用的脚本如下: %SPARK_HOME%/sbin/st ... 
- 【Spark2.0源码学习】-3.Endpoint模型介绍
		Spark作为分布式计算框架,多个节点的设计与相互通信模式是其重要的组成部分. 一.组件概览 对源码分析,对于设计思路理解如下: RpcEndpoint: ... 
- 【Spark2.0源码学习】-9.Job提交与Task的拆分
		在前面的章节Client的加载中,Spark的DriverRunner已开始执行用户任务类(比如:org.apache.spark.examples.SparkPi),下面我们开始针对于用 ... 
- 【Spark2.0源码学习】-6.Client启动
		Client作为Endpoint的具体实例,下面我们介绍一下Client启动以及OnStart指令后的额外工作 一.脚本概览 下面是一个举例: /opt/jdk1..0_79/bin/jav ... 
- 【Spark2.0源码学习】-4.Master启动
		Master作为Endpoint的具体实例,下面我们介绍一下Master启动以及OnStart指令后的相关工作 一.脚本概览 下面是一个举例: /opt/jdk1..0_79/ ... 
- 【Spark2.0源码学习】-5.Worker启动
		Worker作为Endpoint的具体实例,下面我们介绍一下Worker启动以及OnStart指令后的额外工作 一.脚本概览 下面是一个举例: /opt/jdk1..0_79/ ... 
- 【Spark2.0源码学习】-7.Driver与DriverRunner
		承接上一节内容,Client向Master发起RequestSubmitDriver请求,Master将DriverInfo添加待调度列表中(waitingDrivers),下面针对于Dri ... 
随机推荐
- PHP的laravel框架后台实现数据导出excel的功能
			要想在PHP后台实现excel导入导出功能,一种简单有效的方法就是使用phpexcel插件. 要使用phpexcel插件,首先需要下载composer,这个工具是专门用来管理项目中库之间的依赖关系的. ... 
- POJ 3261 出现至少K次的可重叠最长子串
			题意就是给一列数字,求最长的一个子串,并且满足子串在原数串中出现至少K次,子串可以重叠. 解法是将问题转为判定性问题,二分子串的长度,判定是否满足重复至少K次.判定方法是经典的根据子串长度将Heigh ... 
- sass学习入门篇(三)
			这章我们讲“嵌套”,嵌套包括两种:一,选择器嵌套.二是属性的嵌套.一般用选择器嵌套居多 一,选择器嵌套:指的是在一个选择器中嵌套另一个选择器来实现继承.使用&表示父元素选择器 li{ floa ... 
- (原创)看我用各种姿势在手机和PC查看到连接到的wifi密码
			今天一个女神来我家做客,她问我WiFi密码,然而我却奇迹般的忘记了(特么的当时心里一万个草泥马踏过去),让我在她面前尴尬求子的,所以为了防止你们也出现这种情况,我特地把各种方法整理了一下,那么感兴趣的 ... 
- [ext4]磁盘布局 - group分析
			ext4文件系统的磁盘布局是先把磁盘分成一个个相同大小的block块(每个block块的大小默认是4K),然后把这些block块合成一个个group. group大小最大为256M(默认为256M), ... 
- JQuery实现通过点击标题切换字体
			这个主要通过判断被点击的元素的子元素中是否包含了b元素来进行字体的切换,其中wrapInner函数是为了在$author元素的内部添加b标签. 切换回正常字体是通过将内容转化为纯文本形式,再替换元素内 ... 
- 在Ueditor / Umeditor中实现上传图片跨域
			近几天公司的后台管理需要图文编辑文章,但是ueditor提供的方法中,本地图片的上传是通过flash的方式处理的,且不支持跨域.若要在已经前后端分离的Angular项目中使用,需要做复杂的环境配置.跟 ... 
- final的用法
			先来看一段代码 class Car extends Vehicle { public static void main (String[] args) { new C ... 
- Android WebView导入HTML使Js生效的方法
			WebSettings ws = webview.getSettings(); ws.setJavaScriptEnabled(true);//加上这句 webview.loadDataWithBas ... 
- Android自定义评分控件:RatingStarView
			RatingStarView Android自定义的评分控件,类似ProgressBar那样的,使用星星图标(full.half.empty)作为progress标识的评分/打分控件. 效果图 图1: ... 
