Spark 運行流程框架.和shuffle原理

Spark 運行流程框架.和shuffle原理

第一,spark框架原理
在這裏插入圖片描述

我們使用spark-submit提交一個Spark作業之後,這個作業就會啓動一個對應的Driver進程。根據你使用的部署模式(deploy-mode)不同,Driver進程可能在本地啓動,也可能在集羣中某個工作節點上啓動。而Driver進程要做的第一件事情,就是向集羣管理器(可以是Spark Standalone集羣,也可以是其他的資源管理集羣,美團•大衆點評使用的是YARN作爲資源管理集羣)申請運行Spark作業需要使用的資源,這裏的資源指的就是Executor進程。YARN集羣管理器會根據我們爲Spark作業設置的資源參數,在各個工作節點上,啓動一定數量的Executor進程,每個Executor進程都佔有一定數量的內存和CPU core。
  在申請到了作業執行所需的資源之後,Driver進程就會開始調度和執行我們編寫的作業代碼了。Driver進程會將我們編寫的Spark作業代碼分拆爲多個stage,每個stage執行一部分代碼片段,併爲每個stage創建一批Task,然後將這些Task分配到各個Executor進程中執行。Task是最小的計算單元,負責執行一模一樣的計算邏輯(也就是我們自己編寫的某個代碼片段),只是每個Task處理的數據不同而已。一個stage的所有Task都執行完畢之後,會在各個節點本地的磁盤文件中寫入計算中間結果,然後Driver就會調度運行下一個stage。下一個stage的Task的輸入數據就是上一個stage輸出的中間結果。如此循環往復,直到將我們自己編寫的代碼邏輯全部執行完,並且計算完所有的數據,得到我們想要的結果爲止。
  Spark是根據shuffle類算子來進行stage的劃分。如果我們的代碼中執行了某個shuffle類算子(比如reduceByKey、join等),那麼就會在該算子處,劃分出一個stage界限來。可以大致理解爲,shuffle算子執行之前的代碼會被劃分爲一個stage,shuffle算子執行以及之後的代碼會被劃分爲下一個stage。因此一個stage剛開始執行的時候,它的每個Task可能都會從上一個stage的Task所在的節點,去通過網絡傳輸拉取需要自己處理的所有key,然後對拉取到的所有相同的key使用我們自己編寫的算子函數執行聚合操作(比如reduceByKey()算子接收的函數)。這個過程就是shuffle。
  當我們在代碼中執行了cache/persist等持久化操作時,根據我們選擇的持久化級別的不同,每個Task計算出來的數據也會保存到Executor進程的內存或者所在節點的磁盤文件中。
  因此Executor的內存主要分爲三塊:第一塊是讓Task執行我們自己編寫的代碼時使用,默認是佔Executor總內存的20%;第二塊是讓Task通過shuffle過程拉取了上一個stage的Task的輸出後,進行聚合等操作時使用,默認也是佔Executor總內存的20%;第三塊是讓RDD持久化時使用,默認佔Executor總內存的60%。
  Task的執行速度是跟每個Executor進程的CPU core數量有直接關係的。一個CPU core同一時間只能執行一個線程。而每個Executor進程上分配到的多個Task,都是以每個Task一條線程的方式,多線程併發運行的。如果CPU core數量比較充足,而且分配到的Task數量比較合理,那麼通常來說,可以比較快速和高效地執行完這些Task線程。
  以上就是Spark作業的基本運行原理的說明.

在這裏插入圖片描述

  1. 構建Spark Application的運行環境,啓動SparkContext
  2. SparkContext向資源管理器(可以是Standalone,Mesos,Yarn)申請運行Executor資源,並啓動StandaloneExecutorbackend,
  3. Executor向SparkContext申請Task
  4. SparkContext將應用程序分發給Executor
  5. SparkContext構建成DAG圖,將DAG圖分解成Stage、將Taskset發送給Task Scheduler,最後由Task Scheduler將Task發送給Executor運行
  6. Task在Executor上運行,運行完釋放所有資源

第二,spark 的shuffle 過程

在這裏插入圖片描述
shuffle 過程,前一個stage 的 ShuffleMapTask 進行 shuffle write, 把數據存儲在 blockManager 上面, 並且把數據位置元信息上報到 driver 的 mapOutTrack 組件中, 下一個 stage 根據數據位置元信息, 進行 shuffle read, 拉取上個stage 的輸出數據。

現在版本的shuffle機制是SortShuffleManager的運行機制,它主要分成兩種,一種是普通運行機制,另一種是bypass運行機制。當shuffle read task的數量小於等於spark.shuffle.sort.bypassMergeThreshold參數的值時(默認爲200),就會啓用bypass機制。
Sort shuffle的普通機制
圖解:
在這裏插入圖片描述
寫入內存數據結構
該圖說明了普通的SortShuffleManager的原理。在該模式下,數據會先寫入一個內存數據結構中(默認5M),此時根據不同的shuffle算子,可能選用不同的數據結構。如果是reduceByKey這種聚合類的shuffle算子,那麼會選用Map數據結構,一邊通過Map進行聚合,一邊寫入內存;如果是join這種普通的shuffle算子,那麼會選用Array數據結構,直接寫入內存。接着,每寫一條數據進入內存數據結構之後,就會判斷一下,是否達到了某個臨界閾值。如果達到臨界閾值的話,那麼就會嘗試將內存數據結構中的數據溢寫到磁盤,然後清空內存數據結構。
注意:
shuffle中的定時器:定時器會檢查內存數據結構的大小,如果內存數據結構空間不夠,那麼會申請額外的內存,申請的大小滿足如下公式:
applyMemory=nowMenory2-oldMemory
申請的內存=當前的內存情況
2-上一次的內嵌情況
意思就是說內存數據結構的大小的動態變化,如果存儲的數據超出內存數據結構的大小,將申請內存數據結構存儲的數據2-內存數據結構的設定值的內存大小空間。申請到了,內存數據結構的大小變大,內存不夠,申請不到,則發生溢寫
排序
在溢寫到磁盤文件之前,會先根據key對內存數據結構中已有的數據進行排序。
溢寫
排序過後,會分批將數據寫入磁盤文件。默認的batch數量是10000條,也就是說,排序好的數據,會以每批1萬條數據的形式分批寫入磁盤文件。寫入磁盤文件是通過Java的BufferedOutputStream實現的。BufferedOutputStream是Java的緩衝輸出流,首先會將數據緩衝在內存中,當內存緩衝滿溢之後再一次寫入磁盤文件中,這樣可以減少磁盤IO次數,提升性能。
merge
一個task將所有數據寫入內存數據結構的過程中,會發生多次磁盤溢寫操作,也就會產生多個臨時文件。最後會將之前所有的臨時磁盤文件都進行合併,這就是merge過程,此時會將之前所有臨時磁盤文件中的數據讀取出來,然後依次寫入最終的磁盤文件之中。此外,由於一個task就只對應一個磁盤文件,也就意味着該task爲Reduce端的stage的task準備的數據都在這一個文件中,因此還會單獨寫一份索引文件,其中標識了下游各個task的數據在文件中的start offset與end offset。
SortShuffleManager由於有一個磁盤文件merge的過程,因此大大減少了文件數量。比如第一個stage有50個task,總共有10個Executor,每個Executor執行5個task,而第二個stage有100個task。由於每個task最終只有一個磁盤文件,因此此時每個Executor上只有5個磁盤文件,所有Executor只有50個磁盤文件。
注意:
1)block file= 2M
一個map task會產生一個索引文件和一個數據大文件
2) m
r>2m(r>2):SortShuffle會使得磁盤小文件的個數再次的減少
Sort shuffle的bypass機制
在這裏插入圖片描述
bypass運行機制的觸發條件如下:
1)shuffle map task數量小於spark.shuffle.sort.bypassMergeThreshold參數的值。
2)不是聚合類的shuffle算子(比如reduceByKey)。
此時task會爲每個reduce端的task都創建一個臨時磁盤文件,並將數據按key進行hash然後根據key的hash值,將key寫入對應的磁盤文件之中。當然,寫入磁盤文件時也是先寫入內存緩衝,緩衝寫滿之後再溢寫到磁盤文件的。最後,同樣會將所有臨時磁盤文件都合併成一個磁盤文件,並創建一個單獨的索引文件。
該過程的磁盤寫機制其實跟未經優化的HashShuffleManager是一模一樣的,因爲都要創建數量驚人的磁盤文件,只是在最後會做一個磁盤文件的合併而已。因此少量的最終磁盤文件,也讓該機制相對未經優化的HashShuffleManager來說,shuffle read的性能會更好。
而該機制與普通SortShuffleManager運行機制的不同在於:
第一,磁盤寫機制不同;
第二,不會進行排序。也就是說,啓用該機制的最大好處在於,shuffle write過程中,不需要進行數據的排序操作,也就節省掉了這部分的性能開銷

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章