【原】Spark中Stage的提交源码解读
版权声明:本文为原创文章,未经允许不得转载。
复习内容:
Spark中Job如何划分为Stage http://www.cnblogs.com/yourarebest/p/5342424.html
1.Spark中Stage的提交
1.在复习内容中,将Job划分为Stage这一过程的调用起始于方法handleJobSubmitted,同样Stage的提交也包含在该方法中,如下所示:
private[scheduler] def handleJobSubmitted(jobId: Int,
finalRDD: RDD[_],
func: (TaskContext, Iterator[_]) => _,
partitions: Array[Int],
callSite: CallSite,
listener: JobListener,
properties: Properties) {
//(1)根据jobId生成finalStage,详见文章-Spark中Job如何划分为Stage
//(2)Job的提交,详见文章-Spark中Job的提交
//(3)提交stages,但首先循环提交丢失的父Stage(s),即将丢失的stage加入到waitingStages中
//(4)提交Taskset(tasks)
//提交stage,但首先循环提交丢失的父Stage(s),即将丢失的stage加入到waitingStages中,详见2
submitStage(finalStage)
//check for 正在等待或失败的stages ,他们会重新提交
submitWaitingStages()
}
2.submitStage方法如下所示,根据finalStage循环调用submitStage方法进行Stages的提交,
//根据Stage找到jobId
val jobId = activeJobForStage(stage)
if (jobId.isDefined) {
logDebug("submitStage(" + stage + ")")
if (!waitingStages(stage) && !runningStages(stage) && !failedStages(stage)) {
val missing = getMissingParentStages(stage).sortBy(_.id)
logDebug("missing: " + missing)
//如果没有丢失,那么就提交Stage
if (missing.isEmpty) {
logInfo("Submitting " + stage + " (" + stage.rdd + "), which has no missing parents")
submitMissingTasks(stage, jobId.get)详见3
} else {
for (parent <- missing) {
submitStage(parent)
}
waitingStages += stage
}
}
} else {
abortStage(stage, "No active job for stage " + stage.id, None)
}
3.submitMissingTasks方法如下所示,该方法中包括Stage、TaskSet的提交,TaskSet(tasks)的提交请看文章-Spark中TaskSet(Tasks)的提交
private def submitMissingTasks(stage: Stage, jobId: Int) {
logDebug("submitMissingTasks(" + stage + ")")
// Get our pending tasks and remember them in our pendingTasks entry
stage.pendingPartitions.clear()
//首先找到根据ShuffleMapStage和ResultStage两种类型来找到它们对应的分区的索引ids
val (allPartitions: Seq[Int], partitionsToCompute: Seq[Int]) = {
stage match {
case stage: ShuffleMapStage =>
val allPartitions = 0 until stage.numPartitions
val filteredPartitions = allPartitions.filter { id => stage.outputLocs(id).isEmpty }
(allPartitions, filteredPartitions)
case stage: ResultStage =>
val job = stage.resultOfJob.get
val allPartitions = 0 until job.numPartitions
val filteredPartitions = allPartitions.filter { id => !job.finished(id) }
(allPartitions, filteredPartitions)
}
}
//创建一个内部计算器,如果stage没有accumulator被初始化,那么重置内部的accumulator
if (stage.internalAccumulators.isEmpty || allPartitions == partitionsToCompute) {
stage.resetInternalAccumulators()
}
//得到Job的属性
val properties = jobIdToActiveJob.get(stage.firstJobId).map(_.properties).orNull
runningStages += stage
//SparkListenerStageSubmitted应用在测试task是否被serializable后 然后发送出去
//如果task没有序列化,SparkListenerStageCompleted事件将不会发送出去,它总是在SparkListenerStageSubmitted事件之后
outputCommitCoordinator.stageStart(stage.id)
//得到RDD得到它的分区的位置
val taskIdToLocations = try {
stage match {
case s: ShuffleMapStage =>
partitionsToCompute.map { id => (id, getPreferredLocs(stage.rdd, id))}.toMap
case s: ResultStage =>
val job = s.resultOfJob.get
partitionsToCompute.map { id =>
val p = s.partitions(id)
(id, getPreferredLocs(stage.rdd, p))
}.toMap
}
} catch {
case NonFatal(e) =>
stage.makeNewStageAttempt(partitionsToCompute.size)
listenerBus.post(SparkListenerStageSubmitted(stage.latestInfo, properties))
abortStage(stage, s"Task creation failed: $e\n${e.getStackTraceString}", Some(e))
runningStages -= stage
return
}
stage.makeNewStageAttempt(partitionsToCompute.size, taskIdToLocations.values.toSeq)
//给JobProgressListener发送SparkListenerStageSubmitted事件
listenerBus.post(SparkListenerStageSubmitted(stage.latestInfo, properties))
4.SparkListenerStageSubmitted前面我们提到,Job的启动是通过JobProgressListener的onJobStart方法执行的,同样,Stage的提交是通过,对应的事件类型是SparkListenerStageSubmitted,详见下:
override def onStageSubmitted(stageSubmitted: SparkListenerStageSubmitted): Unit = synchronized {
val stage = stageSubmitted.stageInfo
activeStages(stage.stageId) = stage
pendingStages.remove(stage.stageId)
val poolName = Option(stageSubmitted.properties).map {
p => p.getProperty("spark.scheduler.pool", SparkUI.DEFAULT_POOL_NAME)
}.getOrElse(SparkUI.DEFAULT_POOL_NAME)
stageIdToInfo(stage.stageId) = stage
val stageData = stageIdToData.getOrElseUpdate((stage.stageId, stage.attemptId), new StageUIData)
stageData.schedulingPool = poolName
stageData.description = Option(stageSubmitted.properties).flatMap {
p => Option(p.getProperty(SparkContext.SPARK_JOB_DESCRIPTION))
}
val stages = poolToActiveStages.getOrElseUpdate(poolName, new HashMap[Int, StageInfo])
stages(stage.stageId) = stage
for (
activeJobsDependentOnStage <- stageIdToActiveJobIds.get(stage.stageId);
jobId <- activeJobsDependentOnStage;
jobData <- jobIdToData.get(jobId)
) {
jobData.numActiveStages += 1
// If a stage retries again, it should be removed from completedStageIndices set
jobData.completedStageIndices.remove(stage.stageId)
}
}
这样,我们就完成了Stage的提交,下一篇看Task的提交。
【原】Spark中Stage的提交源码解读的更多相关文章
- 【原】 Spark中Task的提交源码解读
版权声明:本文为原创文章,未经允许不得转载. 复习内容: Spark中Stage的提交 http://www.cnblogs.com/yourarebest/p/5356769.html Spark中 ...
- 【原】Spark中Job的提交源码解读
版权声明:本文为原创文章,未经允许不得转载. Spark程序程序job的运行是通过actions算子触发的,每一个action算子其实是一个runJob方法的运行,详见文章 SparkContex源码 ...
- HttpServlet中service方法的源码解读
前言 最近在看<Head First Servlet & JSP>这本书, 对servlet有了更加深入的理解.今天就来写一篇博客,谈一谈Servlet中一个重要的方法-- ...
- sklearn中LinearRegression使用及源码解读
sklearn中的LinearRegression 函数原型:class sklearn.linear_model.LinearRegression(fit_intercept=True,normal ...
- 【原】Spark不同运行模式下资源分配源码解读
版权声明:本文为原创文章,未经允许不得转载. 复习内容: Spark中Task的提交源码解读 http://www.cnblogs.com/yourarebest/p/5423906.html Sch ...
- 15、Spark Streaming源码解读之No Receivers彻底思考
在前几期文章里讲了带Receiver的Spark Streaming 应用的相关源码解读,但是现在开发Spark Streaming的应用越来越多的采用No Receivers(Direct Appr ...
- Spark技术内幕:Stage划分及提交源码分析
http://blog.csdn.net/anzhsoft/article/details/39859463 当触发一个RDD的action后,以count为例,调用关系如下: org.apache. ...
- Spark学习之路 (十六)SparkCore的源码解读(二)spark-submit提交脚本
一.概述 上一篇主要是介绍了spark启动的一些脚本,这篇主要分析一下Spark源码中提交任务脚本的处理逻辑,从spark-submit一步步深入进去看看任务提交的整体流程,首先看一下整体的流程概要图 ...
- Apache Spark源码走读之23 -- Spark MLLib中拟牛顿法L-BFGS的源码实现
欢迎转载,转载请注明出处,徽沪一郎. 概要 本文就拟牛顿法L-BFGS的由来做一个简要的回顾,然后就其在spark mllib中的实现进行源码走读. 拟牛顿法 数学原理 代码实现 L-BFGS算法中使 ...
随机推荐
- java StringBuffer与StringBuilder
StringBuffer:就是字符串缓冲区. * 用于存储数据的容器. * 特点: * 1,长度的可变的. * 2,可以存储不同类型数 ...
- IOS中如何自定义web应用的图标
在iPhone/iPad等苹果移动设备上,可以把网站”添加至主屏幕”,添加时的图标可以在HTML中自定义设置图片. 可以使用apple-touch-icon和apple-touch-icon-prec ...
- PHPCMS 核心代码与 www 分离部署
为了满足更多用户二次开发的兴趣与爱好,同时,为了更加安全.可以通过修改入口代码的包含方式来让主程序和www程序分开. 先看下面目录结构: (图1) 我们需要将 phpcms 目录和 index.php ...
- #Leet Code# Gray Code
描述: 要求相邻数2进制差一位 先获得n-1的列表表示小于 2^(n-1) 的符合要求的列表,加上最高位的加成 2^(n-1) 就是大于等于 2^(n-1) 的符合要求的列表,后者翻转一下就能够与前者 ...
- puppet 部署 horizon server 所需的参数和部署逻辑
所需要的参数: $secret_key, $bind_address = '127.0.0.1', $cache_server_ip = '127.0.0.1', $cache_ser ...
- Source Insight 显示中文乱码
Source Insight 3.X utf8支持插件震撼发布 继上次SI多标签插件之后,因为公司内部编码改为utf8编码,因此特意做了这个Source Insight 3.X utf8插件. 下载地 ...
- vm安装ubuntu桥接模式无法联网
桥接模式,就是和主机不同的ip,其他都是一样的. 编辑网络连接 查看自己机子的ip ipconfig 一般情况下是 ip 192.168.1.XXX 子网掩码 255.255.255.0 网关 192 ...
- Memcached(七)Memcached的并发实例
1. Memcached是什么?Memcached是分布式的内存对象缓存系统. 2. Memcached的基本数据结构是什么?Memcached是基于Key/Value对的HashMap.每一对,都 ...
- Linux下配置jdk1.7
第一步:下载jdk-7-linux-i586.tar.gz wget -c http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-i586 ...
- 如何使一个input文本框随其中内容而变化长度(转)
第一: <input type="text" onkeydown="this.onkeyup();" onkeyup="this.size=(t ...