1.架構
如圖9-5所示,Spark運行架構包括集群資源管理器(Cluster Manager)、運行作業任務的工作節點(Worker Node)、每個應用的任務控制節點(Driver)和每個工作節點上負責具體任務的執行進程(Executor)。其中,集群資源管理器可以是Spark自帶的資源管理器,也可以是YARN或Mesos等資源管理框架。與Hadoop MapReduce計算框架相比,Spark所采用的Executor有兩個優點:一是利用多線程來執行具體的任務(Hadoop MapReduce采用的是進程模型),減少任務的啟動開銷;二是Executor中有一個BlockManager存儲模塊,會將內存和磁盤共同作為存儲設備,當需要多輪迭代計算時,可以將中間結果存儲到這個存儲模塊里,下次需要時,就可以直接讀該存儲模塊里的數據,而不需要讀寫到HDFS等文件系統里,因而有效減少了IO開銷;或者在交互式查詢場景下,預先將表緩存到該存儲系統上,從而可以提高讀寫IO性能。
圖9-5 Spark運行架構
總體而言,如圖9-6所示,在Spark中,一個應用(Application)由一個任務控制節點(Driver)和若干個作業(Job)構成,一個作業由多個階段(Stage)構成,一個階段由多個任務(Task)組成。當執行一個應用時,任務控制節點會向集群管理器(Cluster Manager)申請資源,啟動Executor,并向Executor發送應用程序代碼和文件,然后在Executor上執行任務,運行結束后,執行結果會返回給任務控制節點,或者寫到HDFS或者其他數據庫中。
2.流程
如圖9-7 所示,Spark的基本運行流程如下:(1)當一個Spark應用被提交時,首先需要為這個應用構建起基本的運行環境,即由任務控制節點(Driver)創建一個SparkContext,由SparkContext負責和資源管理器(Cluster Manager)的通信以及進行資源的申請、任務的分配和監控等。SparkContext會向資源管理器注冊并申請運行Executor的資源;(2)資源管理器為Executor分配資源,并啟動Executor進程,Executor運行情況將隨著“心跳”發送到資源管理器上;(3)SparkContext根據RDD的依賴關系構建DAG圖,DAG圖提交給DAG調度器(DAGScheduler)進行解析,將DAG圖分解成多個“階段”(每個階段都是一個任務集),并且計算出各個階段之間的依賴關系,然后把一個個“任務集”提交給底層的任務調度器(TaskScheduler)進行處理;Executor向SparkContext申請任務,任務調度器將任務分發給Executor運行,同時,SparkContext將應用程序代碼發放給Executor;(4)任務在Executor上運行,把執行結果反饋給任務調度器,然后反饋給DAG調度器,運行完畢后寫入數據并釋放所有資源。
圖9-7 Spark運行基本流程圖
總體而言,Spark運行架構具有以下特點:
(1)每個應用都有自己專屬的Executor進程,并且該進程在應用運行期間一直駐留。Executor進程以多線程的方式運行任務,減少了多進程任務頻繁的啟動開銷,使得任務執行變得非常高效和可靠;
(2)Spark運行過程與資源管理器無關,只要能夠獲取Executor進程并保持通信即可;
(3)Executor上有一個BlockManager存儲模塊,類似于鍵值存儲系統(把內存和磁盤共同作為存儲設備),在處理迭代計算任務時,不需要把中間結果寫入到HDFS等文件系統,而是直接放在這個存儲系統上,后續有需要時就可以直接讀?。辉诮换ナ讲樵儓鼍跋?,也可以把表提前緩存到這個存儲系統上,提高讀寫IO性能;
(4)任務采用了數據本地性和推測執行等優化機制。數據本地性是盡量將計算移到數據所在的節點上進行,即“計算向數據靠攏”,因為移動計算比移動數據所占的網絡資源要少得多。而且,Spark采用了延時調度機制,可以在更大的程度上實現執行過程優化。比如,擁有數據的節點當前正被其他的任務占用,那么,在這種情況下是否需要將數據移動到其他的空閑節點呢?答案是不一定。因為,如果經過預測發現當前節點結束當前任務的時間要比移動數據的時間還要少,那么,調度就會等待,直到當前節點可用。