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

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


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

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

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

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


SparkContext
createTaskScheduler
重點需要看createTaskScheduler方法,然后調用start

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



這里的cm(clusterManager)是 YarnClusterManager,scheduler是YarnScheduler, backend是YarnClientSchedulerBackend
YarnClusterManager.initialize() 方法
YarnClusterManager繼承TaskSchedulerImpl,
將Backend作為自己的成員變量,并通過schedulingMode創(chuàng)建調度是FIFOSchedulableBuilder還是FairSchedulableBuilder,這里是提交task的時候用到的調度方式

YarnClientSchedulerBackend
YarnClientSchedulerBackend繼承YarnSchedulerBackend,YarnSchedulerBackend 繼承CoarseGrainedSchedulerBackend

start方法第一部分
首先調用super.start,查看super.start方法為CoarseGrainedSchedulerBackend的start方法

CoarseGrainedSchedulerBackend.start()

這里調用了createDriverEndpointRef,可以看到關鍵詞driver了,其實driver本質上的類是DriverEndpoint,結合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
本質上Driver是CoarseGrainedSchedulerBackend里的一個成員變量,負責序列化并通過RPC發(fā)送給有資源的Executor執(zhí)行task,但是在這里并沒有執(zhí)行,因為還沒有申請到執(zhí)行資源Executor。接下來回到我們的YarnSchedulerBackend中

start方法第二部分
第一部分調用了super.start我們知道了Driver的本質和職責接下來,看第二部分

org.apache.spark.deploy.yarn.Client
Client中有一個yarnClient成員變量,與yarn集群做RPC通信,提交Application使用

org.apache.spark.deploy.yarn.Client. submitApplication

createContainerLaunchContext中會申請ApplicationMaster的啟動信息,并指定啟動類,
- cluster模式: org.apache.spark.deploy.yarn.ApplicationMaster
-
client模式:org.apache.spark.deploy.yarn.ExecutorLauncher
image.png
ExecutorLauncher
什么也沒有做,就是調用了ApplicationMaster的main方法

org.apache.spark.deploy.yarn.ApplicationMaster
會根據(jù)運行模式(client or cluster), 這里是client模式,所以執(zhí)行runExecutorLauncher





通過ExecutorRunnable來啟動Executor

ExecutorRunnable中有nmClient, 就是NodeManagerClient, 通過nmClient與NodeManager RPC通信, 啟動Executor

prepareCommand會指定Executor所啟動的類

這個類就是CoarseGrainedExecutorBackend, 并且會傳入driver url,

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

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

接下來分析 Yarn Cluster模式
Yarn Cluster 總架構
Cluster與Client不同的是,Client的Driver(分配Task)和ApplicationMaster(申請資源)是不在同一個進程里面的,Cluster模式的Driver(分配Task)和ApplicationMaster(申請資源)不同一個進程里

由SparkSubmit圖我們可以知道,Cluster模式里,啟動的是YarnClusterApplication
YarnClusterApplication

org.apache.spark.deploy.yarn.Client
這個是和 client 模式中使用同樣的Client類,不同的是,cluster啟動的是org.apache.spark.deploy.yarn.ApplicationMaster, 前面我們分析知道client模式中org.apache.spark.deploy.yarn.ExecutorLauncher 其實就是調用了ApplicationMaster.main(), 還有一點是cluster模式中,需要啟動driver

ApplicationMaster

runDriver
在ApplicationMaster進程中,通過反射調用userClass, userClass中就會啟動SparkSession, SparkContext等.


分析源碼可以得到下面這個圖,本質上還是用的CoarseGrainedExecutorBackend里的driver

ApplicationMaster里的資源申請(啟動Executor)
邏輯和client分析過程一樣的,就是通過ExecutorRunnable啟動CoarseGrainedExecutorBackend

Yarn Cluster 總架構

總結
本文從源碼,分析Yarn模式下Client&Cluster模式的資源啟動流程,分析Client&Cluster究竟有什么不一樣,本質的不一樣就是Driver和ApplicationMaster在不在同一進程里。
本文如果有錯誤的地方,歡迎指出。
