Spark的應用分爲任務調度和任務執行兩個部分,全部的Spark應用程序都離不開SparkContext和Executor兩部分,Executor負責執行任務,運行Executor的機器稱爲Worker節點,SparkContext由用戶程序啓動,經過資源調度模塊和Executor通訊。算法
具體來講,以SparkContext爲程序運行的總入口,在SparkContext的初始化過程當中,Spark會分別建立DAGScheduler做業調度和TaskScheduler任務調度兩級調度模塊。網絡
其中DAGScheduler是基於任務階段的高層調度模塊,它爲每一個Spark做業計算具備依賴關係的多個調度階段(一般根據shuffle來劃分),而後爲每一個階段構建出一組具體的任務(一般會考慮數據的本地性等),而後以TaskSets(任務組)的形式提交給TaskScheduler來具體執行。而TaskScheduler則負責具體啓動任務、監控和彙報任務運行狀況fetch
(1)在Driver端初始化SparkContext。任何spark的應用程序都包含Driver代碼和Executor代碼。Spark應用程序首先在Driver初始化SparkContext。由於SparkCotext是Spark應用程序通往集羣的惟一路徑,在SparkContext裏面包含了DAGScheduler和TaskScheduler兩個調度器類。在建立SparkContext對象的同時也自動建立了這兩個類。優化
(2)SparkContext初始化完成後,首先根據Spark的相關配置,向Cluster Master申請所須要的資源,而後在各個Worker結點初始化相應的Executor。Executor初始化完成後,Driver將經過對Spark應用程序中的RDD代碼進行解析,生成相應的RDD graph(RDD圖),該圖描述了RDD的相關信息及彼此之間的依賴關係。spa
(3)RDD圖構建完畢後,Driver將提交給DAGScheduler進行解析。DAGScheduler在解析RDD圖的過程當中,當遇到Action算子後將進行逆向解析,根據RDD之間的依賴關係以及是否存在shuffle等,將RDD圖解析成一系列具備前後依賴關係的Stage。Stage以shuffle進行劃分,即若是兩個RDD之間存在寬依賴的關係,DAGScheduler將會在這RDD之間拆分爲兩個Stage進行執行,且只有在前一個Stage(父Stage)執行完畢後,才執行後一個Stage。線程
(4)DAGScheduler將劃分的一系列的Stage(TaskSet),按照Stage的前後順序依次提交給底層的調度器TaskScheduler去執行。對象
(5)TaskScheduler接收到DAGScheduler的Stage任務後,將會在集羣環境中構建一個 TaskSetManager 實例來管理Stage(TaskSet) 的生命週期。blog
(6)TaskSetManager將會把相關的計算代碼、數據資源文件等發送到相應的Executor上,並在相應的Executor上啓動線程池執行。TaskSetManager在執行過程當中,使用了一些優化的算法,用於提升執行的效率,譬如根據數據本地性決定每一個Task最佳位置、推測執行碰到Straggle任務須要放到別的結點上重試、出現shuffle輸出數據丟失時要報告fetch failed錯誤等機制。生命週期
(7)在Task執行的過程當中,可能有部分應用程序涉及到I/O的輸入輸出,在每一個Executor由相應的BlockManager進行管理,相關BlockManager的信息將會與Driver中的Block tracker進行交互和同步。進程
(8)在TaskThreads執行的過程當中,若是存在運行錯誤、或其餘影響的問題致使失敗,TaskSetManager將會默認嘗試3次,嘗試均失敗後將上報TaskScheduler,TaskScheduler若是解決不了,再上報DAGScheduler,DAGScheduler將根據各個Worker結點的運行狀況從新提交到別的Executor中執行。
(9)TaskThreads執行完畢後,將把執行的結果反饋給TaskSetManager,TaskSetManager反饋給TaskScheduler,TaskScheduler再上報DAGScheduler,DAGScheduler將根據是否還存在待執行的Stage,將繼續循環迭代提交給TaskScheduler去執行。
(10)待全部的Stage都執行完畢後,將會最終達到應用程序的目標,或者輸出到文件、或者在屏幕顯示等,Driver的本次運行過程結束,等待用戶的其餘指令或者關閉。
(11)在用戶顯式關閉 SparkContext後,整個運行過程結束,相關的資源被釋放或回收。
從以上工做流程上能夠看出,全部的Spark程序都離不開SparkContext和Executor兩部分,每一個Spark Application都有本身的Executor進程,此進程的生命週期和整個Application的生命週期相同,此進程內部維持着多個線程來並行地執行分配給它的Task。這種運行形式有利於不一樣Application之間的資源調度隔離,但也意味着不一樣的Application之間難以作到相互通訊和信息交換。同時須要注意因爲Driver負責全部的任務調度,因此他應該儘量地靠近Worker結點,若是能在一個網絡環境中那就更好了。