一个Spark job的生命历程
一个job的生命历程
dagScheduler.runJob //(1)
--> submitJob ( eventProcessLoop.post(JobSubmitted,***) //(2)
--> eventProcessLoop //(3)
--> onReceive(event: DAGSchedulerEvent) //(4)
--> doOnReceive(event: DAGSchedulerEvent) //(5)
--> case JobSubmitted //(6)
--> dagScheduler.handleJobSubmitted //(7)
--> finalStage =createResultStage(finalRDD, func, partitions, jobId, callSite) //(8)
--> job = new ActiveJob(jobId, finalStage, callSite, listener, properties) //(9)
--> jobIdToActiveJob(jobId) = job //(10)
--> activeJobs += job //(11)
--> finalStage.setActiveJob(job) //(12)
--> stageIds = jobIdToStageIds(jobId).toArray //(13)
--> stageInfos = stageIds.flatMap(id => stageIdToStage.get(id).map(_.latestInfo)) //(14)
--> listenerBus.post(SparkListenerJobStart(job.jobId, jobSubmissionTime, stageInfos, properties)) //(15)
--> submitStage(finalStage) //(16)
--> getMissingParentStages(stage).sortBy(_.id) //(17)
--> finalStage = getOrCreateShuffleMapStage(dependency, jobId) //(18)
--> createShuffleMapStage(dep, firstJobId) //(19)
-->stage = new ShuffleMapStage(id, rdd, numTasks, parents, jobId, rdd.creationSite, shuffleDep)
--> job = new ActiveJob(jobId, finalStage, callSite, listener, properties) //(20)
--> submitStage(finalStage) //(21)//划分和提交stage算法精髓
--> submitMissingTasks(stage, jobId.get) //(22)
--> submitWaitingChildStages(stage) //(23)
--> markMapStageJobAsFinished(job, mapOutputTracker.getStatistics(dependency)) //(24)
/**
* 获取某个stage的父stage
* 对于一个stage,如果它的最后一个RDD的所有依赖都是窄依赖,将不会创建新的stage
* 如果其RDD会依赖某个RDD,用宽依赖的RDD创建一个新的stage,并立即返回这个stage
* @type {[type]}
*/
private def getMissingParentStages(stage: Stage): List[Stage] = {
val missing = new HashSet[Stage]
val visited = new HashSet[RDD[_]]
val waitingForVisit = new Stack[RDD[_]] def visit(rdd: RDD[_]) {
if (!visited(rdd)) {
visited += rdd
val rddHasUncachedPartitions = getCacheLocs(rdd).contains(Nil)
if (rddHasUncachedPartitions) {
//遍历RDD的依赖,对于每种具有shuffle的操作,如reduceByKey,groupByKey,countByKey,底层对应了3个RDD:
//Map
for (dep <- rdd.dependencies) {
dep match {
//如果是宽依赖
case shufDep: ShuffleDependency[_, _, _] =>
//使用宽依赖的RDD创建一个 ShuffleMapStage,并且将isShuffleMap 设置为true,
//默认最后一个stage不是shuffle不是ShuffleMapStage,但是finalstage之前所有的stage都是ShuffleMapStage
val mapStage = getOrCreateShuffleMapStage(shufDep, stage.firstJobId)
if (!mapStage.isAvailable) {
missing += mapStage
} //如果是窄依赖
case narrowDep: NarrowDependency[_] =>
//将依赖的RDD放入栈中
waitingForVisit.push(narrowDep.rdd)
}
}
}
}
}
//
waitingForVisit.push(stage.rdd)
while (waitingForVisit.nonEmpty) {
//
visit(waitingForVisit.pop())
}
missing.toList
}
override def submitTasks(taskSet: TaskSet) {
val tasks = taskSet.tasks //获取ttaskSet的task列表
logInfo("Adding task set " + taskSet.id + " with " + tasks.length + " tasks")
this.synchronized {
//每个taskSet都会创建一个manager,用于管理每个taskSet,并设定最大失败次数 maxTaskFailures
val manager = createTaskSetManager(taskSet, maxTaskFailures)
val stage = taskSet.stageId
//尝试连接task,如果task失败,会负责重试spark,直到超过重试次数,并且会通知延迟调度
val stageTaskSets =
taskSetsByStageIdAndAttempt.getOrElseUpdate(stage, new HashMap[Int, TaskSetManager])
//通过 manager 获得活着的taskSet
stageTaskSets(taskSet.stageAttemptId) = manager
val conflictingTaskSet = stageTaskSets.exists { case (_, ts) =>
ts.taskSet != taskSet && !ts.isZombie
}
if (conflictingTaskSet) {
throw new IllegalStateException(s"more than one active taskSet for stage $stage:" +
s" ${stageTaskSets.toSeq.map{_._2.taskSet.id}.mkString(",")}")
}
//利用已选择的调度器schedulableBuilder,把一个taskSet的manager加入调度管理池中
/*
def initialize(backend: SchedulerBackend) {
this.backend = backend
schedulableBuilder = {
schedulingMode match {
case SchedulingMode.FIFO =>
new FIFOSchedulableBuilder(rootPool)
case SchedulingMode.FAIR =>
new FairSchedulableBuilder(rootPool, conf)
case _ =>
throw new IllegalArgumentException(s"Unsupported $SCHEDULER_MODE_PROPERTY: " +
s"$schedulingMode")
}
}
schedulableBuilder.buildPools()
}*/
schedulableBuilder.addTaskSetManager(manager, manager.taskSet.properties)
if (!isLocal && !hasReceivedTask) {
starvationTimer.scheduleAtFixedRate(new TimerTask() {
override def run() {
if (!hasLaunchedTask) {
logWarning("Initial job has not accepted any resources; " +
"check your cluster UI to ensure that workers are registered " +
"and have sufficient resources")
} else {
this.cancel()
}
}
}, STARVATION_TIMEOUT_MS, STARVATION_TIMEOUT_MS)
}
hasReceivedTask = true
}
/**
* 创建 taskScheduler 的时候,就是为 taskSchedulerImpl 创建一个 SparkDeploySchedulerBackend .
* 它负责创建AppClient,向master注册Application
*/
backend.reviveOffers()
}
一个Spark job的生命历程的更多相关文章
- 连载《一个程序猿的生命周期》-《发展篇》 - 3.农民与软件工程师,农业与IT业
相关文章:随笔<一个程序猿的生命周期>- 逆潮流而动的“叛逆者” 15年前,依稀记得走出大山,进城求学的场景.尽管一路有父亲的陪伴,但是内心仍然畏惧.当父亲转身离去.准备回到 ...
- Spark记录(二):Spark程序的生命周期
本文以Spark执行模式中最常见的集群模式为例,详细的描述一下Spark程序的生命周期(YARN作为集群管理器). 1.集群节点初始化 集群刚初始化的时候,或者之前的Spark任务完成之后,此时集群中 ...
- 连载《一个程序猿的生命周期》- 44.感谢,我从事了IT相关的工作
感谢博客园一直以来的支持,写连载都是在这里首发,相比较CSDN和开源中国气氛要好的多. 节前,想以此篇文章结束<一个程序猿的生命周期>的<生存>篇,对过10的年做一个了断,准备 ...
- Spark集群 + Akka + Kafka + Scala 开发(2) : 开发一个Spark应用
前言 在Spark集群 + Akka + Kafka + Scala 开发(1) : 配置开发环境,我们已经部署好了一个Spark的开发环境. 本文的目标是写一个Spark应用,并可以在集群中测试. ...
- 连载《一个程序猿的生命周期》-28、被忽悠来的单身HR(女同志)
一个程序猿的生命周期 微信平台 口 号:职业交流,职业规划:面对现实,用心去交流.感悟. 公众号:iterlifetime 百木-ITer职业交流奋斗 群:141588103 微 博:h ...
- 连载《一个程序猿的生命周期》-6、自学C++,二级考过后,为工作的机会打下了基础
一个程序猿的生命周期 微信平台 口 号:职业交流,职业规划:面对现实,用心去交流.感悟. 公众号:iterlifetime 百木-ITer职业交流奋斗 群:141588103 微 博:h ...
- 阅读<构建之法>第13、14、15、16、17章 与 《一个程序员的生命周期》读后感
第十三章 软件测试 这一章介绍了很多关于测试的方法,比如说单元测试,代码覆盖率测试,构建验证测试,验收测试等,我有一个很纠结的问题,如果我开发软件,是把这么多测试全做完,还是挑一些测试来进行呢?如 ...
- 从源码剖析一个Spark WordCount Job执行的全过程
原文地址:http://mzorro.me/post/55c85d06e40daa9d022f3cbd WordCount可以说是分布式数据处理框架的”Hello World”,我们可以以它为 ...
- 连载《一个程序猿的生命周期》-《发展篇》 - 7.是什么阻碍了"程序猿"的发展?
有两件事想记录一下,具有普遍性和代表性."程序猿"加了引号,是泛指一类人,也并非局限于IT行业. 山东子公司的总经理是公司大股东之一,个子不高.有些秃顶.面容显老,但看 ...
随机推荐
- 详解MathType引用公式编号功能
在论文创作期间,如果需要在文本中删除大量的公式,手动编号删除的工作量是比较大的,使用MathType引用公式编号功能就可以节约大量的时间,提供很大的方便.本教程将详解MathType引用公式编号功能. ...
- MVC 5 视图之公用代码
一.公共模板 1.@RenderBody() 在网站公用部分通过一个占位符@RenderBody()来为网站独立部分预留一个位置.然后私有页面顶部通过@{Layout="公用模板路径&quo ...
- TTCN中PTC的执行流程
一些概念 Component(測试组件或者測试成分),TTCN接触下来最频繁的就是MTC(Main Test Component,主測试组件),在执行測试用例前,须要首先创建一个MTC.在testca ...
- UVa 10450 - World Cup Noise
题目:构造一个01串,使得当中的1不相邻,问长度为n的串有多少中. 分析:数学,递推数列. 设长度为n的串有n个.则有递推关系:f(n)= f(n-1)+ f(n-2): 长度为n的结束可能是0或者1 ...
- day7_直播_网络编程篇(元昊老师著)
网络编程篇计算机网络: 多台独立的计算机用网络通信设备连接起来的网络.实现资源共享和数据传递. 比如,我们之前的学过的知识可以将D盘的一个文件传到C盘,但如果你想从你的电脑传一个文件到我的电脑上目前是 ...
- raw_input()
raw_input() 用于接收标准输入,并把标准输入当成字符串类型来处理,只能在 Python2 中使用,Python3 中没有这个函数 #!/usr/bin/env python #-*- cod ...
- ContentPriver
共享应用程序内的数据, 在数据修改时可以监听 1.特点 ①.可以将应用中的数据对外进行共享: ②.数据访问方式统一,不必针对不同数据类型采取不同的访问策略: ③.内容提供者将数据封装,只暴露出我们希望 ...
- 小程序的movable-view怎么持续移动
在小程序的官方例子中,点击按钮以后的movable-view只是挪动了一次(链接:https://mp.weixin.qq.com/debug/wxadoc/dev/component/movable ...
- (一)微信小程序之模拟调用后台接口踩过的坑
如下图标记的三个点 在调试过程中出现问题,特此记录. 1. 之前在浏览器测试接口习惯省略 http:// ,是因为浏览器默认有一个检测,在你输入的网址前面加http://,如果有就不加. 然而在微信小 ...
- PHP面向对象 实例化 构造函数 封装 继承 静态
PHP面向对象 实例化 构造函数 封装 继承 静态 面向对象: 一:定义类 class Dog { var $name; var $age; var $pinzhong; function Jiao( ...