本文帶讀者從源碼查看,分析Standalone模式下Client&Cluster模式的資源啟動流程,分析Client&Cluster究竟有什么不一樣
回顧
在xxxx中我們分析了Standalone模式下Master和Worker的啟動流程。

- Master負(fù)責(zé)集群總資源的管理,包括CPU、內(nèi)存的分配以及所有Applications的管理、Cluster模式下還有所有的driver的管理。Master啟動后會定時清理沒有上報心跳的Worker
- Master啟動后會向Master注冊自己(RegisterWorker),將自己的CPU cores和內(nèi)存大小上報給Master,并定時發(fā)送心跳,更新Master里面屬于自己ID的時間戳
資源有了,接下來需要啟動我們自己的Application。
SparkSubmit提交代碼


通過分析spark-submit腳本,我們知道最終啟動的是SparkSubmit類,接下來的調(diào)用流程如下所示。

最終通過prepareSumitEnvironment解析出mainClass,最終在SparkApplication start方法中,通過反射調(diào)用MainClass的main方法,解析的MainClass如下

Standalone Client 源碼分析
由上可知,最終我們解析的是用戶的Class,而最重要的類就是SparkContext,高版本是SparkSession,本質(zhì)是將SparkContext作為SparkSession的成員變量。
Standalone Client 總架構(gòu)

SparkSession
SparkSession將SparkContext作為的自己成員變量


SparkContext
createTaskScheduler
重點需要看createTaskScheduler方法,然后調(diào)用start

TaskSchedulerImpl
這里會創(chuàng)建TaskSchedulerImpl和StandaloneSchedulerBackend,并通過initialize將StandaloneSchedulerBackend放入TaskSchedulerImpl中,結(jié)合上圖,會調(diào)用StandaloneSchedulerBackend的start方法

initialize
將Backend作為自己的成員變量,并通過schedulingMode創(chuàng)建調(diào)度是FIFOSchedulableBuilder還是FairSchedulableBuilder,這里是提交task的時候用到的調(diào)度方式

StandaloneSchedulerBackend
start方法第一部分
首先調(diào)用super.start,查看super.start方法為CoarseGrainedSchedulerBackend的start方法

CoarseGrainedSchedulerBackend.start()

這里調(diào)用了createDriverEndpointRef,可以看到關(guān)鍵詞driver了,其實driver本質(zhì)上的類是DriverEndpoint,結(jié)合Spark RPC框架,我們可以知道Driver的生命周期方法。
onStart() 和 receive
這里啟動一個定時線程,定時給自己發(fā)送ReviveOffers,給自己發(fā)送case class ReviveOffers

makeOffers
通過命名方式我們可以知道,這里是在獲取可用的executors的資源,將task信息包裝成taskDescs,在Executor上啟動task

將task序列化后發(fā)送給Executor,但是這里并未真正執(zhí)行,因為還沒有申請到Executor資源,所以onstart里的定時線程將會一直嘗試執(zhí)行,直到申請到executor,就會在上面launchTasks

Driver
本質(zhì)上Driver是CoarseGrainedSchedulerBackend里的一個成員變量,負(fù)責(zé)序列化并通過RPC發(fā)送給有資源的Executor執(zhí)行task,但是在這里并沒有執(zhí)行,因為還沒有申請到執(zhí)行資源Executor。接下來回到我們的StandaloneSchedulerBackend中

start方法第二部分
第一部分調(diào)用了super.start我們知道了Driver的本質(zhì)和職責(zé)接下來,看第二部分

將需要啟動的Executor本質(zhì)上是org.apache.spark.executor.CoarseGrainedExecutorBackend類以及App所需要的資源cores 、內(nèi)存等數(shù)據(jù),和最重要的,第一部分super.start()啟動的DriverEndpoint的driverUrl信息,封裝到ApplicationDescription中,并啟動StandaloneAppClient,將ApplicationDescription設(shè)置為StandaloneAppClient成員變量然后啟動
StandaloneAppClient

ClientEndpoint onStart
向Master注冊Application


Master接受到后,告訴Client注冊成功


然后Master通過schedule調(diào)度分配Executor, 發(fā)送RPC在相應(yīng)的Worker上啟動Executor,實際就是Client發(fā)送給Master的org.apache.spark.executor.CoarseGrainedExecutorBackend


Worker接收到命令后開始啟動Executor,所以下一步就是Excutor(CoarseGrainedExecutorBackend)的main方法
Worker 啟動Exeutor
通過線程的方式,通過ExecutorRunner來啟動Executor進程


Executor 啟動
CoarseGrainedExecutorBackend也是一個EndPoint,所以也會走RPC的生命周期方法,一個很重要的點是,Client -> Master->Worker ->Executor將driverUrl的信息傳遞給Executor,Executor啟動后根據(jù)driverUrl向driverUrl反向注冊自己

Driver接收到Executor注冊后,運算資源已經(jīng)有了,DriverEndpoint里的開始調(diào)度,如果有Task,就開始LaunchTask,到此,StandAlone Client源碼分析完畢

Standalone Cluster 總架構(gòu)
Cluster與Client不同的是,Client的Driver(分配Task)和Client(申請資源)是在同一個類里面的UserClass里,Cluster模式的Driver(分配Task)和Client(申請資源)不在同一個進程里

由SparkSubmit圖我們可以知道,Cluster模式里,啟動的是spark.deploy.ClientApp
spark.deploy.ClientApp
啟動ClientEndpoint,注意,此時的ClientEndpoint與Client模式下的不是同一個類,類名一樣,包名不一樣

org.apache.spark.deploy.ClientEndpoint
將Driver信息封裝到driverDescription,主類是DriverWrapper,向Master注冊RequestSubmitDriver(driverDescription)

Master啟動通知Worker啟動Driver(DriverWrapper)



Worker啟動Driver,和啟動Executor使用ExecutorRunner線程啟動進程類似 ,Driver使用的是DriverRunner線程啟動,主類就是DriverWrapper
DriverWrapper
通過反射調(diào)用UserClass,接下來的申請資源,和分配Task的過程與Client沒有本質(zhì)的區(qū)別

Standalone Cluster 總架構(gòu)

總結(jié)
本文從源碼,分析Standalone模式下Client&Cluster模式的資源啟動流程,分析Client&Cluster究竟有什么不一樣,本質(zhì)的不一樣就是Driver進程是在客戶端機器還是在集群的Worker的某臺機器上。
本文如果有錯誤的地方,歡迎指出。