Spark中的Scheduler
scheduler分成两个类型,一个是TaskScheduler与其实现,一个是DAGScheduler。
TaskScheduler:主要负责各stage中传入的task的执行与调度。
DAGScheduler:主要负责对JOB中的各种依赖进行解析,根据RDD的依赖生成stage并通知TaskScheduler执行。
实例生成
TaskScheduler实例生成:
scheduler实例生成,我目前主要是针对onyarn的spark进行的相关分析,
在appmaster启动后,通过调用startUserClass()启动线程来调用用户定义的spark分析程序。
传入的第一个参数为appmastername(master),可传入的如:yarn-cluster等。
在用户定义的spark分析程序中,生成SparkContext实例。
通过SparkContext.createTaskScheduler函数。如果是yarn-cluster,生成YarnClusterScheduler实例。
此部分生成的scheduler为TaskScheduler实例。
defthis(sc:SparkContext) = this(sc,newConfiguration())
同时YarnClusterSchduler实现TaskSchedulerImpl。
defthis(sc:SparkContext) = this(sc,sc.conf.getInt("spark.task.maxFailures",4))
生成TaskScheduler中的SchedulerBackend属性引用,yarn-cluster为CoarseGrainedSchedulerBackend
valbackend =newCoarseGrainedSchedulerBackend(scheduler,sc.env.actorSystem)
scheduler.initialize(backend)
DAGScheduler实例生成:
classDAGScheduler(
taskSched: TaskScheduler,
mapOutputTracker:MapOutputTrackerMaster,
blockManagerMaster:BlockManagerMaster,
env: SparkEnv)
extendsLogging {
defthis(taskSched:TaskScheduler){
this(taskSched,SparkEnv.get.mapOutputTracker.asInstanceOf[MapOutputTrackerMaster],
SparkEnv.get.blockManager.master,SparkEnv.get)
}
taskSched.setDAGScheduler(this)
scheduler调度过程分析
1.rdd执行action操作,如saveAsHadoopFile
2.调用SparkContext.runJob
3.调用DAGScheduler.runJob-->此函数调用submitJob,并等job执行完成。
Waiter.awaitResult()中通过_jobFinished检查job运行是否完成,如果完成,此传为true,否则为false.
_jobFinished的值通过resultHandler函数,每调用一次finishedTasks的值加一,
如果finishedTasks的个数等于totalTasks的个数时,表示完成。或者出现exception.
defrunJob[T, U: ClassTag](
rdd: RDD[T],
func: (TaskContext, Iterator[T])=> U,
partitions: Seq[Int],
callSite: String,
allowLocal: Boolean,
resultHandler: (Int, U) =>Unit,
properties: Properties = null)
{
valwaiter =submitJob(rdd, func, partitions, callSite, allowLocal, resultHandler,properties)
waiter.awaitResult()match{
caseJobSucceeded => {}
caseJobFailed(exception:Exception, _) =>
logInfo("Failedto run " + callSite)
throwexception
}
}
4.调用DAGScheduler.submitJob函数,
部分代码:生成JobWaiter实例,并传入此实例,发送消息,调用JobSubmitted事件。并返回waiter实例。
JobWaiter是JobListener的实现。
valwaiter =newJobWaiter(this,jobId,partitions.size, resultHandler)
eventProcessActor! JobSubmitted(
jobId,rdd, func2,partitions.toArray, allowLocal, callSite, waiter,properties)
waiter
5.处理DAGScheduler的JobSubmitted事件消息,通过processEvent处理消息接收的事件。
defreceive = {
caseevent:DAGSchedulerEvent =>
logTrace("Gotevent of type " +event.getClass.getName)
if(!processEvent(event)){
submitWaitingStages()
} else{
resubmissionTask.cancel()
context.stop(self)
}
}
}))
6.processEvent函数中处理JobSubmitted事件部分代码:
caseJobSubmitted(jobId,rdd, func,partitions,allowLocal,callSite,listener,properties)=>
varfinalStage:Stage = null
try{
生成stage实例,stage的id通过nextStageId的值加一得到,task的个数就是partitions的分区个数,
根据job对应的rdd,得到如果parentrdd是shuffle的rdd时生成ShuffleMapStage,通过getParentStages函数,
此处去拿到parentrdd时,如果currentrdd的parentrdd不是shuffle,递归调用parentrdd,
如果parendrdd中没有shuffle的rdd,不生成新的stage,否则有多少个,生成多少个。此处是处理DAG类的依赖
finalStage= newStage(rdd,partitions.size,None, jobId,Some(callSite))
} catch{
casee:Exception =>
logWarning("Creatingnew stage failed due to exception - job: "+ jobId, e)
listener.jobFailed(e)
returnfalse
}
生成ActiveJob实例。设置numFinished的值为0,表示job中有0个完成的task.
设置所有task个数的arrayfinished.并把所有元素的值设置为false.把JobWaiter当listener传入ActiveJob.
valjob = newActiveJob(jobId,finalStage,func,partitions,callSite,listener,properties)
对已经cache过的TaskLocation进行清理。
clearCacheLocs()
logInfo("Gotjob " + job.jobId+ " ("+ callSite+ ") with "+ partitions.length+
"output partitions (allowLocal=" +allowLocal+ ")")
logInfo("Finalstage: " + finalStage+ " ("+ finalStage.name+ ")")
logInfo("Parentsof final stage: " +finalStage.parents)
logInfo("Missingparents: " +getMissingParentStages(finalStage))
如果runJob时传入的allowLocal的值为true,同时没有需要shuffle的rdd,同时partitions的长度为1,
也就是