Spark調優:提交job資源參數調優及內存模型調優

 【場景】

Spark提交作業job的時候要指定該job可以使用的CPU、內存等資源參數,生產環境中,任務資源分配不足會導致該job執行中斷、失敗等問題,所以對Spark的job資源參數分配調優非常重要。

spark提交作業,yarn-cluster模式示例:

./bin/spark-submit\

--class com.ww.rdd.wordcount \

--master yarn \

--deploy-mode cluster \
--executor-memory 4G \
--num-executors 50 \

--driver-memory 1G \

--conf spark.default.parallelism=1000 \

--conf spark.memory.fraction=0.75 \

--conf spark.memory.storageFraction=0.5 \

/home/spark/wordcount.jar \
1000  #入參


【參數】
num-executors

參數說明:該參數用於設置每個Spark作業總共要用多少個Executor進程來執行。例如Driver向YARN集羣管理器申請資源時,YARN集羣管理器會盡可能按照該配置在集羣的各個worker節點上啓動相應數量的Executor進程。這個參數非常重要,如果不設置的話,Spark默認只啓動少量的Executor進程,意味着該Spark作業並行度不足,如果作業計算多、數據很大,會導致運行速度非常慢甚至資源不足,異常中斷,無法完成等。

調優建議:num-executors設置太少或太多的Executor進程都不好。設置的太少,無法充分利用集羣資源;設置的太多的話,大部分隊列可能無法給予充分的資源。生產環境摸索的經驗是每個Spark作業的運行一般設置50~100個左右的Executor進程比較合適。

 
executor-memory

參數說明:該參數用於設置每個Executor進程的內存。Executor內存的大小,很多時候直接決定了Spark作業的性能,而且跟常見的JVM OOM異常,也有直接的關係。

調優建議:如果內存資源充足的前提下,一般每個job給每個Executor進程的內存設置4G~8G較爲合適,供參考。具體的設置還得根據Spark集羣可以佔用的內存資源總量來定。num-executors * executor-memory,是本Spark作業申請到的內存資源量,這個值是不能超過Spark集羣可以佔用的內存資源總量的。

 

executor-cores

參數說明:該參數用於設置每個Executor進程的CPU cores數量。這個參數決定了每個Executor進程並行執行task線程的能力。因爲每個CPU core同一時間只能執行一個task線程,因此每個Executor進程的CPU cores數量越多,越能夠快速地並行執行完分配給自己的所有task線程。

調優建議:如果CPU核數資源充足的前提下,一般每個job給每個Executor的CPU core數量設置爲2~4個較爲合適,供參考。具體的設置還得根據Spark集羣可以佔用的CPU core數量資源總量來定。num-executors * executor-cores,是本Spark作業申請到的CPU core數量,這個值是不能超過Spark集羣可以佔用的CPU core數量資源總量的。

 

driver-memory

參數說明:該參數用於設置Driver進程的內存。

調優建議:Driver的內存通常來說不設置,或者設置1G左右應該就夠了。唯一需要注意的一點是,如果需要使用collect算子將RDD的數據全部拉取到Driver上進行處理,那麼必須確保Driver的內存足夠大,否則會出現OOM內存溢出的問題。

 

spark.default.parallelism

參數說明:該參數用於設置每個stage的默認task數量。這個參數極爲重要,如果不設置可能會直接影響Spark作業性能。

調優建議:如果不設置這個參數,會導致Spark自己根據底層HDFS的block數量來設置task的數量,默認是一個HDFS block對應一個task。通常來說,Spark默認設置的數量是偏少的(比如就幾十個task),如果task數量偏少的話,就會導致你前面設置好的Executor的參數都前功盡棄。試想一下,無論Executor進程有多少個,內存和CPU資源分配有多充足,但是task只有1個或者10個,那麼90%的Executor進程可能根本就沒有task執行,也就是白白浪費了寶貴的內存和CPU資源!因此Spark官網建議的設置原則是,設置該參數爲num-executors * executor-cores的2~3倍較爲合適,例如,Executor的總CPU core數量爲300個,那麼設置1000個task是可以的,此時可以充分地利用Spark集羣的資源,也就是說,1個cpu core併發跑2~3個task是較爲合適的。

spark.memory.fraction、spark.memory.storageFraction


【Spark內存模型】

    Spark在一個executor中的內存分爲3塊:storage內存、execution內存、other內存。

1. storage內存:存儲broadcast,cache,persist數據的地方。

2. execution內存:執行內存,join、aggregate、map等shuffle中間結果都緩存在這部分內存中,滿了再寫入磁盤,能夠減少IO。其實map過程也是在這個內存中執行的。

3. other內存:程序代碼執行時預留給自己的內存。

其中,execution和storage是Spark的Executor中內存的佔用大戶,other佔用內存相對少很多。

 
【spark1.6.0之前版本】

spark1.6.0之前版本,execution和storage的內存分配是獨立配置的,使用的參數配置分別是:

spark.storage.memoryFraction:storage內存佔Executor總內存比例,default 0.6。

spark.shuffle.memoryFraction:execution內存佔Executor總內存比例,default 0.2。

spark1.6.0之前版本,上述兩塊內存是互相隔離的,無法空閒借用。這就導致了Executor的內存利用率不高,而且需要根據Application的具體情況,使用者自己來調節這兩個參數優化Spark的內存使用。

 
【spark1.6.0及之後版本】

spark1.6.0及之後版本,execution內存和storage內存支持合併配置,使用的參數配置分別是:

spark.memory.fraction:“execution內存+storage內存” 佔Executor總內存比例,default 0.75。

spark.memory.storageFraction:storage內存 默認 佔Executor總內存比例,default 0.5,如果運行時不夠用,且execution內存有空閒,可以借用execution內存。

execution內存和storage內存可以相互借用,提高了內存的Spark中內存的使用率,同時也減少了OOM的情況。

 
【其他】

1.spark.memory.useLegacyMode:默認值是false,也就是使用上述spark1.6.0及之後版本新的內存管理模型,推薦使用。如果非要想用老的spark1.6.0之前版本老的內存管理模型,配置爲true。

2.如果發現task由於頻繁的gc導致運行緩慢(通過spark web ui可以觀察到作業的gc耗時),意味着task執行用戶代碼的內存,也就是上述other內存不夠用,嘗試調低execution和storage內存看看。

參考:
https://www.cnblogs.com/wwcom123/p/10561806.html
https://www.cnblogs.com/wwcom123/p/10549714.html

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