Spark資料收藏--------Spark執行架構

後開啟撒打發了發表於2018-01-31

1、 Spark執行架構

1.1 術語定義

lApplication:Spark Application的概念和Hadoop MapReduce中的類似,指的是使用者編寫的Spark應用程式,包含了一個Driver 功能的程式碼和分佈在叢集中多個節點上執行的Executor程式碼;

lDriver:Spark中的Driver即執行上述Application的main()函式並且建立SparkContext,其中建立SparkContext的目的是為了準備Spark應用程式的執行環境。在Spark中由SparkContext負責和ClusterManager通訊,進行資源的申請、任務的分配和監控等;當Executor部分執行完畢後,Driver負責將SparkContext關閉。通常用SparkContext代表Drive;

lExecutor:Application執行在Worker 節點上的一個程式,該程式負責執行Task,並且負責將資料存在記憶體或者磁碟上,每個Application都有各自獨立的一批Executor。在Spark on Yarn模式下,其程式名稱為CoarseGrainedExecutorBackend,類似於Hadoop MapReduce中的YarnChild。一個CoarseGrainedExecutorBackend程式有且僅有一個executor物件,它負責將Task包裝成taskRunner,並從執行緒池中抽取出一個空閒執行緒執行Task。每個CoarseGrainedExecutorBackend能並行執行Task的數量就取決於分配給它的CPU的個數了;

lCluster Manager:指的是在叢集上獲取資源的外部服務,目前有:

Ø  Standalone:Spark原生的資源管理,由Master負責資源的分配;

Ø  Hadoop Yarn:由YARN中的ResourceManager負責資源的分配;

lWorker:叢集中任何可以執行Application程式碼的節點,類似於YARN中的NodeManager節點。在Standalone模式中指的就是通過Slave檔案配置的Worker節點,在Spark on Yarn模式中指的就是NodeManager節點;

l作業(Job):包含多個Task組成的平行計算,往往由Spark Action催生,一個JOB包含多個RDD及作用於相應RDD上的各種Operation;

l階段(Stage):每個Job會被拆分很多組Task,每組任務被稱為Stage,也可稱TaskSet,一個作業分為多個階段;

l任務(Task): 被送到某個Executor上的工作任務;

clip_image002

1.2 Spark執行基本流程

Spark執行基本流程參見下面示意圖

1.   構建Spark Application的執行環境(啟動SparkContext),SparkContext向資源管理器(可以是Standalone、Mesos或YARN)註冊並申請執行Executor資源;

2.   資源管理器分配Executor資源並啟動StandaloneExecutorBackend,Executor執行情況將隨著心跳傳送到資源管理器上;

3.   SparkContext構建成DAG圖,將DAG圖分解成Stage,並把Taskset傳送給Task Scheduler。Executor向SparkContext申請Task,Task Scheduler將Task發放給Executor執行同時SparkContext將應用程式程式碼發放給Executor。

4.   Task在Executor上執行,執行完畢釋放所有資源。

clip_image004

Spark執行架構特點:

l每個Application獲取專屬的executor程式,該程式在Application期間一直駐留,並以多執行緒方式執行tasks。這種Application隔離機制有其優勢的,無論是從排程角度看(每個Driver排程它自己的任務),還是從執行角度看(來自不同Application的Task執行在不同的JVM中)。當然,這也意味著Spark Application不能跨應用程式共享資料,除非將資料寫入到外部儲存系統。

lSpark與資源管理器無關,只要能夠獲取executor程式,並能保持相互通訊就可以了。

l提交SparkContext的Client應該靠近Worker節點(執行Executor的節點),最好是在同一個Rack裡,因為Spark Application執行過程中SparkContext和Executor之間有大量的資訊交換;如果想在遠端叢集中執行,最好使用RPC將SparkContext提交給叢集,不要遠離Worker執行SparkContext。

lTask採用了資料本地性和推測執行的優化機制。

1.2.1 DAGScheduler

DAGScheduler把一個Spark作業轉換成Stage的DAG(Directed Acyclic Graph有向無環圖),根據RDD和Stage之間的關係找出開銷最小的排程方法,然後把Stage以TaskSet的形式提交給TaskScheduler,下圖展示了DAGScheduler的作用:

clip_image006

1.2.2 TaskScheduler

DAGScheduler決定了執行Task的理想位置,並把這些資訊傳遞給下層的TaskScheduler。此外,DAGScheduler還處理由於Shuffle資料丟失導致的失敗,這有可能需要重新提交執行之前的Stage(非Shuffle資料丟失導致的Task失敗由TaskScheduler處理)。

TaskScheduler維護所有TaskSet,當Executor向Driver傳送心跳時,TaskScheduler會根據其資源剩餘情況分配相應的Task。另外TaskScheduler還維護著所有Task的執行狀態,重試失敗的Task。下圖展示了TaskScheduler的作用:

clip_image008

在不同執行模式中任務排程器具體為:

l  Spark on Standalone模式為TaskScheduler;

l  YARN-Client模式為YarnClientClusterScheduler

l  YARN-Cluster模式為YarnClusterScheduler

1.3 RDD執行原理

那麼 RDD在Spark架構中是如何執行的呢?總高層次來看,主要分為三步:

1.建立 RDD 物件

2.DAGScheduler模組介入運算,計算RDD之間的依賴關係。RDD之間的依賴關係就形成了DAG

3.每一個JOB被分為多個Stage,劃分Stage的一個主要依據是當前計算因子的輸入是否是確定的,如果是則將其分在同一個Stage,避免多個Stage之間的訊息傳遞開銷。

clip_image010

以下面一個按 A-Z 首字母分類,查詢相同首字母下不同姓名總個數的例子來看一下 RDD 是如何執行起來的。

clip_image011

步驟 1 :建立 RDD  上面的例子除去最後一個 collect 是個動作,不會建立 RDD 之外,前面四個轉換都會建立出新的 RDD 。因此第一步就是建立好所有RDD( 內部的五項資訊 ) 。

步驟 2 :建立執行計劃 Spark 會盡可能地管道化,並基於是否要重新組織資料來劃分 階段 (stage) ,例如本例中的 groupBy() 轉換就會將整個執行計劃劃分成兩階段執行。最終會產生一個 DAG(directed acyclic graph ,有向無環圖 ) 作為邏輯執行計劃。

clip_image012

步驟 3 :排程任務  將各階段劃分成不同的 任務 (task) ,每個任務都是資料和計算的合體。在進行下一階段前,當前階段的所有任務都要執行完成。因為下一階段的第一個轉換一定是重新組織資料的,所以必須等當前階段所有結果資料都計算出來了才能繼續。

假設本例中的 hdfs://names 下有四個檔案塊,那麼 HadoopRDD 中 partitions 就會有四個分割槽對應這四個塊資料,同時 preferedLocations 會指明這四個塊的最佳位置。現在,就可以建立出四個任務,並排程到合適的叢集結點上。

clip_image014

 

2、Spark在不同叢集中的執行架構

Spark注重建立良好的生態系統,它不僅支援多種外部檔案儲存系統,提供了多種多樣的叢集執行模式。部署在單臺機器上時,既可以用本地(Local)模式執行,也可以使用偽分散式模式來執行;當以分散式叢集部署的時候,可以根據自己叢集的實際情況選擇Standalone模式(Spark自帶的模式)、YARN-Client模式或者YARN-Cluster模式。Spark的各種執行模式雖然在啟動方式、執行位置、排程策略上各有不同,但它們的目的基本都是一致的,就是在合適的位置安全可靠的根據使用者的配置和Job的需要執行和管理Task。

2.1 Spark on Standalone執行過程

Standalone模式是Spark實現的資源排程框架,其主要的節點有Client節點、Master節點和Worker節點。其中Driver既可以執行在Master節點上中,也可以執行在本地Client端。當用spark-shell互動式工具提交Spark的Job時,Driver在Master節點上執行;當使用spark-submit工具提交Job或者在Eclips、IDEA等開發平臺上使用”new SparkConf.setManager(“spark://master:7077”)”方式執行Spark任務時,Driver是執行在本地Client端上的。

其執行過程如下:

1.SparkContext連線到Master,向Master註冊並申請資源(CPU Core 和Memory);

2.Master根據SparkContext的資源申請要求和Worker心跳週期內報告的資訊決定在哪個Worker上分配資源,然後在該Worker上獲取資源,然後啟動StandaloneExecutorBackend;

3.StandaloneExecutorBackend向SparkContext註冊;

4.SparkContext將Applicaiton程式碼傳送給StandaloneExecutorBackend;並且SparkContext解析Applicaiton程式碼,構建DAG圖,並提交給DAG Scheduler分解成Stage(當碰到Action操作時,就會催生Job;每個Job中含有1個或多個Stage,Stage一般在獲取外部資料和shuffle之前產生),然後以Stage(或者稱為TaskSet)提交給Task Scheduler,Task Scheduler負責將Task分配到相應的Worker,最後提交給StandaloneExecutorBackend執行;

5.StandaloneExecutorBackend會建立Executor執行緒池,開始執行Task,並向SparkContext報告,直至Task完成。

6.所有Task完成後,SparkContext向Master登出,釋放資源。

clip_image016

2.2  Spark on YARN執行過程

YARN是一種統一資源管理機制,在其上面可以執行多套計算框架。目前的大資料技術世界,大多數公司除了使用Spark來進行資料計算,由於歷史原因或者單方面業務處理的效能考慮而使用著其他的計算框架,比如MapReduce、Storm等計算框架。Spark基於此種情況開發了Spark on YARN的執行模式,由於藉助了YARN良好的彈性資源管理機制,不僅部署Application更加方便,而且使用者在YARN叢集中執行的服務和Application的資源也完全隔離,更具實踐應用價值的是YARN可以通過佇列的方式,管理同時執行在叢集中的多個服務。

Spark on YARN模式根據Driver在叢集中的位置分為兩種模式:一種是YARN-Client模式,另一種是YARN-Cluster(或稱為YARN-Standalone模式)。

2.2.1 YARN框架流程

任何框架與YARN的結合,都必須遵循YARN的開發模式。在分析Spark on YARN的實現細節之前,有必要先分析一下YARN框架的一些基本原理。

Yarn框架的基本執行流程圖為:

clip_image018

其中,ResourceManager負責將叢集的資源分配給各個應用使用,而資源分配和排程的基本單位是Container,其中封裝了機器資源,如記憶體、CPU、磁碟和網路等,每個任務會被分配一個Container,該任務只能在該Container中執行,並使用該Container封裝的資源。NodeManager是一個個的計算節點,主要負責啟動Application所需的Container,監控資源(記憶體、CPU、磁碟和網路等)的使用情況並將之彙報給ResourceManager。ResourceManager與NodeManagers共同組成整個資料計算框架,ApplicationMaster與具體的Application相關,主要負責同ResourceManager協商以獲取合適的Container,並跟蹤這些Container的狀態和監控其進度。

2.2.2 YARN-Client

Yarn-Client模式中,Driver在客戶端本地執行,這種模式可以使得Spark Application和客戶端進行互動,因為Driver在客戶端,所以可以通過webUI訪問Driver的狀態,預設是http://hadoop1:4040訪問,而YARN通過http:// hadoop1:8088訪問。

YARN-client的工作流程分為以下幾個步驟:

clip_image020

1.Spark Yarn Client向YARN的ResourceManager申請啟動Application Master。同時在SparkContent初始化中將建立DAGScheduler和TASKScheduler等,由於我們選擇的是Yarn-Client模式,程式會選擇YarnClientClusterScheduler和YarnClientSchedulerBackend;

2.ResourceManager收到請求後,在叢集中選擇一個NodeManager,為該應用程式分配第一個Container,要求它在這個Container中啟動應用程式的ApplicationMaster,與YARN-Cluster區別的是在該ApplicationMaster不執行SparkContext,只與SparkContext進行聯絡進行資源的分派;

3.Client中的SparkContext初始化完畢後,與ApplicationMaster建立通訊,向ResourceManager註冊,根據任務資訊向ResourceManager申請資源(Container);

4.一旦ApplicationMaster申請到資源(也就是Container)後,便與對應的NodeManager通訊,要求它在獲得的Container中啟動啟動CoarseGrainedExecutorBackend,CoarseGrainedExecutorBackend啟動後會向Client中的SparkContext註冊並申請Task;

5.Client中的SparkContext分配Task給CoarseGrainedExecutorBackend執行,CoarseGrainedExecutorBackend執行Task並向Driver彙報執行的狀態和進度,以讓Client隨時掌握各個任務的執行狀態,從而可以在任務失敗時重新啟動任務;

6.應用程式執行完成後,Client的SparkContext向ResourceManager申請登出並關閉自己。

 

2.2.3 YARN-Cluster

在YARN-Cluster模式中,當使用者向YARN中提交一個應用程式後,YARN將分兩個階段執行該應用程式:第一個階段是把Spark的Driver作為一個ApplicationMaster在YARN叢集中先啟動;第二個階段是由ApplicationMaster建立應用程式,然後為它向ResourceManager申請資源,並啟動Executor來執行Task,同時監控它的整個執行過程,直到執行完成。

YARN-cluster的工作流程分為以下幾個步驟:


clip_image022

1.   Spark Yarn Client向YARN中提交應用程式,包括ApplicationMaster程式、啟動ApplicationMaster的命令、需要在Executor中執行的程式等;

2.   ResourceManager收到請求後,在叢集中選擇一個NodeManager,為該應用程式分配第一個Container,要求它在這個Container中啟動應用程式的ApplicationMaster,其中ApplicationMaster進行SparkContext等的初始化;

3.   ApplicationMaster向ResourceManager註冊,這樣使用者可以直接通過ResourceManage檢視應用程式的執行狀態,然後它將採用輪詢的方式通過RPC協議為各個任務申請資源,並監控它們的執行狀態直到執行結束;

4.   一旦ApplicationMaster申請到資源(也就是Container)後,便與對應的NodeManager通訊,要求它在獲得的Container中啟動啟動CoarseGrainedExecutorBackend,CoarseGrainedExecutorBackend啟動後會向ApplicationMaster中的SparkContext註冊並申請Task。這一點和Standalone模式一樣,只不過SparkContext在Spark Application中初始化時,使用CoarseGrainedSchedulerBackend配合YarnClusterScheduler進行任務的排程,其中YarnClusterScheduler只是對TaskSchedulerImpl的一個簡單包裝,增加了對Executor的等待邏輯等;

5.   ApplicationMaster中的SparkContext分配Task給CoarseGrainedExecutorBackend執行,CoarseGrainedExecutorBackend執行Task並向ApplicationMaster彙報執行的狀態和進度,以讓ApplicationMaster隨時掌握各個任務的執行狀態,從而可以在任務失敗時重新啟動任務;

6.   應用程式執行完成後,ApplicationMaster向ResourceManager申請登出並關閉自己。

 

2.2.4 YARN-Client 與 YARN-Cluster 區別

理解YARN-Client和YARN-Cluster深層次的區別之前先清楚一個概念:Application Master。在YARN中,每個Application例項都有一個ApplicationMaster程式,它是Application啟動的第一個容器。它負責和ResourceManager打交道並請求資源,獲取資源之後告訴NodeManager為其啟動Container。從深層次的含義講YARN-Cluster和YARN-Client模式的區別其實就是ApplicationMaster程式的區別。

l  YARN-Cluster模式下,Driver執行在AM(Application Master)中,它負責向YARN申請資源,並監督作業的執行狀況。當使用者提交了作業之後,就可以關掉Client,作業會繼續在YARN上執行,因而YARN-Cluster模式不適合執行互動型別的作業;

l  YARN-Client模式下,Application Master僅僅向YARN請求Executor,Client會和請求的Container通訊來排程他們工作,也就是說Client不能離開。

clip_image024 clip_image026

3、Spark在不同叢集中的執行演示

在以下執行演示過程中需要啟動Hadoop和Spark叢集,其中Hadoop需要啟動HDFS和YARN,啟動過程可以參見第三節《Spark程式設計模型(上)--概念及Shell試驗》。

3.1 Standalone執行過程演示

在Spark叢集的節點中,40%的資料用於計算,60%的記憶體用於儲存結果,為了能夠直觀感受資料在記憶體和非記憶體速度的區別,在該演示中將使用大小為1G的Sogou3.txt資料檔案(參見第三節《Spark程式設計模型(上)--概念及Shell試驗》的3.2測試資料檔案上傳),通過對比得到差距。

3.1.1 檢視測試檔案存放位置

使用HDFS命令觀察Sogou3.txt資料存放節點的位置

$cd /app/hadoop/hadoop-2.2.0/bin

$hdfs fsck /sogou/SogouQ3.txt -files -blocks -locations

通過可以看到該檔案被分隔為9個塊放在叢集中

clip_image028

3.1.2啟動Spark-Shell

通過如下命令啟動Spark-Shell,在演示當中每個Executor分配1G記憶體

$cd /app/hadoop/spark-1.1.0/bin

$./spark-shell --master spark://hadoop1:7077 --executor-memory 1g

通過Spark的監控介面檢視Executors的情況,可以觀察到有1個Driver 和3個Executor,其中hadoop2和hadoop3啟動一個Executor,而hadoop1啟動一個Executor和Driver。在該模式下Driver中執行SparkContect,也就是DAGSheduler和TaskSheduler等程式是執行在節點上,進行Stage和Task的分配和管理。

clip_image030

3.1.3執行過程及結果分析

第一步   讀取檔案後計算資料集條數,並計算過程中使用cache()方法對資料集進行快取

val sogou=sc.textFile("hdfs://hadoop1:9000/sogou/SogouQ3.txt")

sogou.cache()

sogou.count()

通過頁面監控可以看到該作業分為8個任務,其中一個任務的資料來源於兩個資料分片,其他的任務各對應一個資料分片,即顯示7個任務獲取資料的型別為(NODE_LOCAL),1個任務獲取資料的型別為任何位置(ANY)。

clip_image032

在儲存監控介面中,我們可以看到快取份數為3,大小為907.1M,快取率為38%

clip_image034

執行結果得到資料集的數量為1000萬筆資料,總共花費了352.17秒

clip_image036

第二步   再次讀取檔案後計算資料集條數,此次計算使用快取的資料,對比前後

sogou.count()

通過頁面監控可以看到該作業還是分為8個任務,其中3個任務資料來自記憶體(PROCESS_LOCAL),3個任務資料來自本機(NODE_LOCAL),其他2個任務資料來自任何位置(ANY)。任務所耗費的時間多少排序為:ANY> NODE_LOCAL> PROCESS_LOCAL,對比看出使用記憶體的資料比使用本機或任何位置的速度至少會快2個數量級。

clip_image038

整個作業的執行速度為34.14秒,比沒有快取提高了一個數量級。由於剛才例子中資料只是部分快取(快取率38%),如果完全快取速度能夠得到進一步提升,從這體驗到Spark非常耗記憶體,不過也夠快、夠鋒利!

clip_image040

3.2 YARN-Client執行過程演示

3.2.1 啟動Spark-Shell

通過如下命令啟動Spark-Shell,在演示當中分配3個Executor、每個Executor為1G記憶體

$cd /app/hadoop/spark-1.1.0/bin

$./spark-shell --master YARN-client --num-executors 3 --executor-memory 1g

第一步   把相關的執行JAR包上傳到HDFS中

clip_image042

通過HDFS檢視介面可以看到在 /user/hadoop/.sparkStaging/應用編號,檢視到這些檔案:

clip_image044

第二步   啟動Application Master,註冊Executor

應用程式向ResourceManager申請啟動Application Master,在啟動完成後會分配Cotainer並把這些資訊反饋給SparkContext,SparkContext和相關的NM通訊,在獲得的Container上啟動Executor,從下圖可以看到在hadoop1、hadoop2和hadoop3分別啟動了Executor

clip_image046

第三步   檢視啟動結果

YARN-Client模式中,Driver在客戶端本地執行,這種模式可以使得Spark Application和客戶端進行互動,因為Driver在客戶端所以可以通過webUI訪問Driver的狀態,預設是http://hadoop1:4040訪問,而YARN通過http:// hadoop1:8088訪問。

clip_image048

clip_image050

3.2.2 執行過程及結果分析

第一步   讀取檔案後計算資料集條數,並計算過程中使用cache()方法對資料集進行快取

val sogou=sc.textFile("hdfs://hadoop1:9000/sogou/SogouQ3.txt")

sogou.cache()

sogou.count()

通過頁面監控可以看到該作業分為8個任務,其中一個任務的資料來源於兩個資料分片,其他的任務各對應一個資料分片,即顯示7個任務獲取資料的型別為(NODE_LOCAL),1個任務獲取資料的型別為任何位置(RACK_LOCAL)。

clip_image052

通過執行日誌可以觀察到在所有任務結束的時候,由 YARNClientScheduler通知YARN叢集任務執行完畢,回收資源,最終關閉SparkContext,整個過程耗費108.6秒。

clip_image054

第二步   檢視資料快取情況

通過監控介面可以看到,和Standalone一樣38%的資料已經快取在記憶體中

clip_image056

第三步   再次讀取檔案後計算資料集條數,此次計算使用快取的資料,對比前後

sogou.count()

通過頁面監控可以看到該作業還是分為8個任務,其中3個任務資料來自記憶體(PROCESS_LOCAL),4個任務資料來自本機(NODE_LOCAL),1個任務資料來自機架(RACK_LOCAL)。對比在記憶體中的執行速度最快,速度比在本機要快至少1個數量級。

clip_image058

YARNClientClusterScheduler替代了Standalone模式下得TaskScheduler進行任務管理,在任務結束後通知YARN叢集進行資源的回收,最後關閉SparkContect。部分快取資料執行過程耗費了29.77秒,比沒有快取速度提升不少。

clip_image060

3.3 YARN-Cluster執行過程演示

3.3.1 執行程式

通過如下命令啟動Spark-Shell,在演示當中分配3個Executor、每個Executor為512M記憶體

$cd /app/hadoop/spark-1.1.0

$./bin/spark-submit --master YARN-cluster --class class3.SogouResult --executor-memory 512m LearnSpark.jar hdfs://hadoop1:9000/sogou/SogouQ3.txt  hdfs://hadoop1:9000/class3/output2

第一步   把相關的資源上傳到HDFS中,相對於YARN-Client多了LearnSpark.jar檔案

clip_image062

這些檔案可以在HDFS中找到,具體路徑為 http://hadoop1:9000/user/hadoop/.sparkStaging/應用編號 :

clip_image064

第二步   YARN叢集接管執行

首先YARN叢集中由ResourceManager分配Container啟動SparkContext,並分配執行節點,由SparkConext和NM進行通訊,獲取Container啟動Executor,然後由SparkContext的YarnClusterScheduler進行任務的分發和監控,最終在任務執行完畢時由YarnClusterScheduler通知ResourceManager進行資源的回收。

clip_image066

3.3.2 執行結果

在YARN-Cluster模式中命令介面只負責應用的提交,SparkContext和作業執行均在YARN叢集中,可以從http:// hadoop1:8088檢視到具體執行過程,執行結果輸出到HDFS中,如下圖所示:

clip_image068

4、問題解決

4.1 YARN-Client啟動報錯

在進行Hadoop2.X 64bit編譯安裝中由於使用到64位虛擬機器,安裝過程中出現下圖錯誤:

[hadoop@hadoop1 spark-1.1.0]$ bin/spark-shell --master YARN-client --executor-memory 1g --num-executors 3

Spark assembly has been built with Hive, including Datanucleus jars on classpath

Exception in thread "main" java.lang.Exception: When running with master 'YARN-client' either HADOOP_CONF_DIR or YARN_CONF_DIR must be set in the environment.

        at org.apache.spark.deploy.SparkSubmitArguments.checkRequiredArguments(SparkSubmitArguments.scala:182)

        at org.apache.spark.deploy.SparkSubmitArguments.<init>(SparkSubmitArguments.scala:62)

        at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:70)

        at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)

clip_image070

 

參考資料:

(1)《Spark1.0.0 執行架構基本概念》 http://blog.csdn.net/book_mmicky/article/details/25714419

(2)《Spark架構與作業執行流程簡介》 http://www.cnblogs.com/shenh062326/p/3658543.html

(3)《Spark1.0.0 執行架構基本概念》 http://shiyanjun.cn/archives/744.html

相關文章