【原】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算法中使 ...
随机推荐
- Winfrom 中 ComboBox 绑定数据后设置选定项问题
在为 ComboBox 当定数据的时候,如果遇到界面显示需要用文本,而获取选定项的值时需要用数字,我们就很习惯使用 DataSource 来进行绑定. 例如以下代码: List<TextVal ...
- inline-block的兼容性问题
inline-block的兼容性问题 Inline-block是元素display属性的一个值.这个名字的由来是因为,display设置这个值的元素,兼具行内元素( inline elements)跟 ...
- css important
!important是CSS1就定义的语法,作用是提高指定样式规则的应用优先权.语法格式{ cssRule !important },即 写在定义的最后面,例如:box{color:red !impo ...
- JVM 优化问题
jvm 优化问题 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...
- ECshop网店系统百万级商品量性能优化-加快首页访问速度
如果ECshop的商品数达到几万,十几万的时候,如果首页没有缓存,第一次访问的时候,你会发现其慢无比,原因就是清空了Cache后或者没有Cache的情况下,ECshop会Bulid一些Cache数据, ...
- Html学习_简易个人网页制作
应用学到的内容,制作简易个人网页 <!DOCTYPE html> <html> <head> <title>Jane.liu</title> ...
- Python多线程学习笔记
Python中与多线程相关的模块有 thread, threading 和 Queue等,thread 和threading模块允许程序员创建和管理线程.thread模块提供了基本的线程和锁的支持,而 ...
- Codeforces Round #334 (Div. 1) C. Lieges of Legendre
Lieges of Legendre 题意:有n堆牛,每堆有ai头牛.两个人玩一个游戏,游戏规则为: <1>从任意一个非空的堆中移走一头牛: <2>将偶数堆2*x变成k堆,每堆 ...
- Shell面试题
1.用Shell编程,判断一文件是不是块或字符设备文件,如果是将其拷贝到 /dev 目录下. #!/bin/bash#1.sh#判断一文件是不是字符或块设备文件,如果是将其拷贝到 /dev 目录下#f ...
- .net faq
http://www.indiabix.com/technical/dotnet/ http://www.codeproject.com/Articles/637480/Csharp-and-ASP- ...