Spark源码分析

整个spark应用程序的运行分成三个阶段:

1、编写代码,使用spark-submit去交任务到集群运行,一直到我们自己编写的main方法运行为止

1、编写代码

2、打成jar

3、编写sprak-submit脚本提交任务

4、脚本解析和执行最终转到main方法执行

SparkSubmit

 

2、sparkContext的初始化

new SparkContext(sparkConf)

 两条线:

1、在driver端执行的各种代码

491-500行:

初始化了 TaskScheduler -----> TaskSchedulerImpl

初始化了 SchedulerBackend -----> StandAloneSchedulerBackend

初始化了 DAGScheduler -----> DAGScheduler

209-210

1758

 

2、在worker和master端执行的各种代码

业务功能实现:

1、master注册

2、worker负责启动executor

 

SparkContext中 500:

_taskScheduler.start()

 

TaskSchedulerImpl中164:

backend.start()

 

这个方法有两个重点:

1、super.start()

driverActor

创建:

CoarseGrainedSchedulerBackend中的391行:

driverEndpoint = createDriverEndpointRef(properties)

2、114-120

clientActor

创建:

(如果说是看的spark-1.x(RPC: akka)的源码,当前这两个对象:

clientActor: spark2.x(RPC:netty)中的 StandaloneAppClient中的 ClientEndPoint

EndPoint的概念等同于了Spark1.x中的Actor

EndPoint是netty中的概念

Actor是AKKA中的概念

)

actor receive preStart

endPoint receive onStart

转到 StandAloneAppClinet类中的  86:

// 开始注册

registerWithMaster(1)

 

转到124行:

tryRegisterAllMasters()

 

转到107行:

masterRef.send(RegisterApplication(appDescription, self))

 

masterRef: Spark集群的主节点:master中的其中一个actor

 

转到Master这个类中的259行:

case RegisterApplication(description, driver)

 

重点有三句代码:

266行:registerApplication(app)

 

269行:driver.send(RegisteredApplication(app.id, self))

 

270行: schedule()

作用就是调度资源,然后在worker中启动executor

 

schedule()执行后转到735行:

 

两个重点:

1、launchDriver(worker, driver)

启动ExecutorBackend

 

其实launchDriver中的driver就是这个对象:

CoarseGrainedExecutorBackend

 

2、startExecutorsOnWorkers()

转到682行:

分配资源给Executor,启动Executor

 

转到708行:

launchExecutor(worker, exec)

启动和加载运行Executor

 

转到Worker类的479行:

LaunchExecutor 真正启动Executor的逻辑代码

 

转到532行:

manager.start()

 

转到ExecutorRunner中的73行:

fetchAndRunExecutor()

 

最终拼装了一个java -Xmx1000M Executor

启动了Executor

初始化Executor的时候:

两个重点:

1、初始化线程池

Executor中89行:

private val threadPool = {

Executors.newCachedThreadPool(threadFactory).asInstanceOf[ThreadPoolExecutor]

}

如果Executor对象创建成功了,就意味着线程池也初始化成功了。

那就意味着:Exzecutor启动成功。

所以等到任务提交过来即可

 

在executor启动成功之后,进行反向注册:

executor 向 driverActor 注册

 

 

从Master中的:748行, executor都启动成功

当Executor启动成功之后:

750行:

exec.application.driver.send(ExecutorAdded)

注册到clientActor之上

 

----------------------到此为止,一个Executor启动成功------------------------------

----------------------当所有的executor都启动成功了之后,整个sparkContext对象初始化成功------------------------------

 

2、等到任务的提交

174行-178行:

def launchTask(context: ExecutorBackend, taskDescription: TaskDescription): Unit = {

val tr = new TaskRunner(context, taskDescription)

runningTasks.put(taskDescription.taskId, tr)

threadPool.execute(tr)

}

 

3、action算子触发任务的提交和执行:sc.runJob()

collect

当一个程序中,碰到第一个actoin算子的时候,就相当于触发了 sc.runJob方法执行

转到:

SparkContext中的2034行:

dagScheduler.runJob(rdd, cleanedFunc, partitions, callSite, resultHandler, localProperties.get)

 

转到DAGScheduler中的632行:

val waiter = submitJob(rdd, func, partitions, callSite, resultHandler, properties)

 

转到604行:

eventProcessLoop.post(JobSubmitted)

 

转到1829行:

dagScheduler.handleJobSubmitted(jobId, rdd, func, partitions, callSite, listener, properties)

 

三个重点:

1、867行:切分stage

finalStage = createResultStage

 

2、激活job

val job = new ActiveJob(jobId, finalStage, callSite, listener, properties)

 

3、提交stage

submitStage(finalStage)

 

转到947行提交任务:

submitMissingTasks(stage, jobId.get)

转到1088行: 是在DAGScheduler当中调用的。

taskScheduler.submitTasks(new TaskSet(

tasks.toArray, stage.id, stage.latestInfo.attemptNumber, jobId, properties))

但是最后:

DAGScheduler的submitMissingTasks方法就把stage变成了一个TaskSet对象

最终转到

taskScheduler中的submitTasks执行

 

要点核心结论:

DAGScheduler会给一个job切分成多个stage

然后把每一个stage提交给taskScheduler去执行

 

DAGScheduler的工作:

从action算子开始:

到把stage变成TaskSet提交到taskScheduler中去执行结束

 

从TaskSchedulerImpl类中的submitTasks方法(180行)去分析:

重点代码:最后一句:

213行:

backend.reviveOffers()

转到:

CoarseGrainedSchedulerBackend类中的136行:

makeOffers()

 

转到251行:

launchTasks(taskDescs)

 

转到CoarseGrainedExecutorBackend中的98行:

executor.launchTask(this, taskDesc)

 

转到Executor中的177行:

threadPool.execute(tr)

 

sparkContext.stop();

等到线程池接收到所有的任务之后,以此执行成功,最终整个Application执行成功

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值