在前面的內容,咱們針對於RpcEndpoint啓動以及RpcEndpoint消息處理機制進行了詳細的介紹,在咱們的大腦裏,基本上能夠構建Spark各節點的模樣。接下來的章節將會從Spark如何從業務代碼分解爲Spark的任務,並最終調度這些任務進行詳細的介紹。
前面針對於Client啓動過程以及Driver進行了詳細的描述,下面咱們根據用戶代碼中的SparkContext這個API類進行解讀,該類Spark用戶代碼執行的基礎,後續咱們會陸續介紹,下面針對於SparkContext以及SparkContext運行過程當中產生的Application進行介紹。
1、SparkContext建立過程
SparkContext在新建時
- 內部建立一個SparkEnv,SparkEnv內部建立一個RpcEnv
-
- RpcEnv內部建立並註冊一個MapOutputTrackerMasterEndpoint(該Endpoint暫不介紹)
- 接着建立DAGScheduler,TaskSchedulerImpl,SchedulerBackend
-
- TaskSchedulerImpl建立時建立SchedulableBuilder,SchedulableBuilder根據類型分爲FIFOSchedulableBuilder,FairSchedulableBuilder兩類
- 最後啓動TaskSchedulerImpl,TaskSchedulerImpl啓動SchedulerBackend
-
- SchedulerBackend啓動時建立ApplicationDescription,DriverEndpoint, StandloneAppClient
- StandloneAppClient內部包括一個ClientEndpoint
2、
SparkContext簡易結構與交互關係
- SparkContext:是用戶Spark執行任務的上下文,用戶程序內部使用Spark提供的Api直接或間接建立一個SparkContext
- SparkEnv:用戶執行的環境信息,包括通訊相關的端點
- RpcEnv:SparkContext中遠程通訊環境
- ApplicationDescription:應用程序描述信息,主要包含appName, maxCores, memoryPerExecutorMB, coresPerExecutor, Command(
CoarseGrainedExecutorBackend), appUiUrl等
- ClientEndpoint:客戶端端點,啓動後向Master發起註冊RegisterApplication請求
- Master:接受RegisterApplication請求後,進行Worker資源分配,並向分配的資源發起LaunchExecutor指令
- Worker:接受LaunchExecutor指令後,運行ExecutorRunner
- ExecutorRunner:運行applicationDescription的Command命令,最終Executor,同時向DriverEndpoint註冊Executor信息
3、
Master對Application資源分配
當Master接受Driver的RegisterApplication請求後,放入waitingDrivers隊列中,在同一調度中進行資源分配,分配過程以下:
waitingApps與aliveWorkers進行資源匹配
- 若是waitingApp配置了app.desc.coresPerExecutor:
-
- 輪詢全部有效可分配的worker,每次分配一個executor,executor的核數爲minCoresPerExecutor(app.desc.coresPerExecutor),直到不存在有效可分配資源或者app依賴的資源已所有被分配
- 若是waitingApp沒有配置app.desc.coresPerExecutor:
-
- 輪詢全部有效可分配的worker,每一個worker分配一個executor,executor的核數爲從minCoresPerExecutor(爲固定值1)開始遞增,直到不存在有效可分配資源或者app依賴的資源已所有被分配
- 其中有效可分配worker定義爲知足一次資源分配的worker:
-
- cores知足:usableWorkers(pos).coresFree - assignedCores(pos) >= minCoresPerExecutor,
- memory知足(若是是新的Executor):usableWorkers(pos).memoryFree - assignedExecutors(pos) * memoryPerExecutor >= memoryPerExecutor
- 注意:Master針對於applicationInfo進行資源分配時,只有存在有效可用的資源就直接分配,而分配剩餘的app.coresLeft則等下一次再進行分配
4、
Worker建立Executor
(圖解:橙色組件是Endpoint組件)
Worker啓動Executor
- 在Worker的tempDir下面建立application以及executor的目錄,並chmod700操做權限
- 建立並啓動ExecutorRunner進行Executor的建立
- 向master發送Executor的狀態狀況
ExecutorRnner
- 新線程【ExecutorRunner for [executorId]】讀取ApplicationDescription將其中Command轉化爲本地的Command命令
- 調用Command並將日誌輸出至executor目錄下的stdout,stderr日誌文件中,Command對應的java類爲CoarseGrainedExecutorBackend
CoarseGrainedExecutorBackend
- 建立一個SparkEnv,建立ExecutorEndpoint(CoarseGrainedExecutorBackend),以及WorkerWatcher
- ExecutorEndpoint建立並啓動後,向DriverEndpoint發送RegisterExecutor請求並等待返回
- DriverEndpoint處理RegisterExecutor請求,返回ExecutorEndpointRegister的結果
- 若是註冊成功,ExecutorEndpoint內部再建立Executor的處理對象
至此,Spark運行任務的容器框架就搭建完成