spark task與stage數量過多調優

Mark_ZQ發表於2020-11-29

圖片發自簡書App

昨天群裡的一個朋友出現了任務執行過慢。

通過執行過程來看,我們發現task比較多,更值得注意的是這些task都在一個stage之中。

首先要分析這個問題我們應該要清楚task和stage的關係。

 

圖片發自簡書App

通過這個圖我們可以看出job-stage-task的對應關係。首先job的劃分是遇到action操作時,被發現後經過sparkcontext的runjob方法來到DAGscheduler,這個類中它會通過依賴關係劃分出stage,一個stage是一個taskset,裡面的每個task對應著rdd的一個分割槽。task可以理解為並行的分片。

 

理解了一個分割槽對應一個task後,可以分析得出這個問題是分割槽過多造成的問題。

那麼我們再來看看分割槽數是怎麼設定的。

如果在spark-default.conf中沒有顯示設定的話。會按照不同模式給不同的預設分割槽數。(spark.default.parallelism)

對於local[N]模式,因為開闢了N個執行緒,所以有N個core,也就預設分割槽為N。如果單用local那麼只會開起一個分割槽。

如果是偽分佈模式,local-cluster[x,y,z] 那麼預設分割槽是x*y,x代表的是執行的executor數量,y是每個executor有多少個core。

如果是yarn或者是standalone模式。是用的函式max(x*y,2)前者的含義和偽分佈一樣,後者表示如果x*y<2,分割槽就取2。

在程式讀取建立RDD的時候,一般會用textFile,這個函式可以讀取本地或者是hdfs的檔案。分割槽數為

rdd的分割槽數 = max(本地file的分片數, sc.defaultMinPartitions)
rdd的分割槽數 = max(hdfs檔案的block數目, sc.defaultMinPartitions)

 

但是對於用 sc.parallelize建立的資料,是用的預設分割槽,也可以在第二個引數中進行顯示的設定。

 

對於問題本身:task過多,原因是分割槽的問題。我們應該從分割槽入手,是輸入的小檔案太多,還是本來就會有大資料量。在分割槽過多時,限定分割槽個數看看效能是否提高,也可以在filter等操作後對分割槽進行一定縮減。大量使用shuffle操作使task增加(這個應該不是本問題原因,但是我們應該考慮這也是讓task增加的原因),這樣會完成多個stage序列會降低效率。

 

當我們真的無法避免這麼多task時候,我們應該用最佳的引數進行調優。下面引數是來自浪尖的建議

1) executor_cores*num_executors 不宜太小或太大!一般不超過總佇列 cores 的 25%,比如佇列總 cores 400,最大不要超過100,最小不建議低於 40,除非日誌量很小。

 

2) executor_cores 不宜為1!否則 work 程式中執行緒數過少,一般 2~4 為宜。

3) executor_memory 一般 6~10g 為宜,最大不超過 20G,否則會導致 GC 代價過高,或資源浪費嚴重。

4) spark_parallelism 一般為 executor_cores*num_executors 的 1~4 倍,系統預設值 64,不設定的話會導致 task 很多的時候被分批序列執行,或大量 cores 空閒,資源浪費嚴重。

5) driver-memory 早前有同學設定 20G,其實 driver 不做任何計算和儲存,只是下發任務與yarn資源管理器和task互動,除非你是 spark-shell,否則一般 1-2g 就夠了。

 

相關文章