Spark 效能調優--資源調優

lightwing發表於2021-09-09

資源調優

在開發完Spark作業之後,就該為作業配置合適的資源了。Spark的資源引數,基本都可以在spark-submit命令中作為引數設定

Spark作業基本執行原理

圖片描述

Spark作業基本執行原理

  1. spark-submit提交一個Spark作業之後,這個作業就會啟動一個對應的Driver程式

  2. 根據你使用的部署模式(deploy-mode:client/cluster)不同,Driver程式可能在本地啟動,也可能在叢集中某個工作節點上啟動

  3. Driver程式本身會根據我們設定的引數,佔有一定數量的記憶體和CPU Core

  4. Driver程式要做的第一件事情,就是向叢集管理器(可以是Spark Standalone叢集,也可以是YARN)申請執行Spark作業需要使用的資源。資源指的就是Executor程式。在各個工作節點上,啟動一定數量的Executor程式,每個Executor程式都佔有一定數量的記憶體和CPU Core

  5. 在申請到了作業執行所需的資源之後,Driver程式就會開始排程和執行我們編寫的作業程式碼了

  6. Driver程式會將我們編寫的Spark作業程式碼分拆為多個Stage,每個Stage執行一部分程式碼片段,併為每個Stage建立一批Task,然後將這些Task分配到各個Executor程式中執行

  7. Task是最小的計算單元,負責執行一模一樣的計算邏輯(也就是我們編寫的某個程式碼片段),只是每個Task處理的資料不同而已。一個Stage的所有Task都執行完畢之後,會在各個節點本地的磁碟檔案中寫入計算中間結果,然後Driver就會排程執行下一個Stage。下一個Stage的Task的輸入資料就是上一個Stage輸出的中間結果

  8. Spark是根據Shuffle類運算元來進行Stage的劃分,Shuffle運算元執行之前的程式碼會被劃分為一個Stage

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執行緒


資源引數調優

num-executors
設定Spark作業總共要用多少個Executor程式來執行
Driver在向YARN叢集管理器申請資源時,YARN叢集管理器會盡可能按照你的設定來在叢集的各個工作節點上,啟動相應數量的Executor程式

每個Spark作業的執行一般設定50~100個左右(根據叢集的規模)的Executor程式比較合適,設定太少或太多的Executor程式都不好。設定的太少,無法充分利用叢集資源;設定的太多的話,大部分佇列可能無法給予充分的資源

executor-memory
設定每個Executor程式的記憶體
Executor記憶體的大小,很多時候直接決定了Spark作業的效能,而且跟常見的JVM OOM異常,也有直接的關聯

每個Executor程式的記憶體設定4G~8G較為合適,num-executors乘以executor-memory,是不能超過佇列的最大記憶體量的,Spark叢集可以設定每個executor最多使用的記憶體大小。如果你是跟團隊裡其他人共享這個資源佇列,那麼申請的記憶體量最好不要超過資源佇列最大總記憶體的1/3~1/2

executor-cores
設定每個Executor程式的CPU core數量
決定了每個Executor程式並行執行task執行緒的能力

數量設定為2~4個較為合適,依據資源佇列的最大CPU Core限制是多少,再依據設定的Executor數量,來決定每個Executor程式可以分配到幾個CPU Core

driver-memory
設定Driver程式的記憶體
Driver的記憶體通常來說不設定,或者設定1G左右應該就夠了

如果需要使用 collect 運算元將RDD的資料全部拉取到Driver上進行處理,那麼必須確保Driver的記憶體足夠大,否則會出現OOM記憶體溢位的問題

spark.default.parallelism
設定每個stage的預設task數量
不去設定這個引數,那麼Spark根據底層HDFS的block數量來設定task的數量,預設是一個HDFS block對應一個task,通常來說,Spark預設設定的數量是偏少的

設定該引數為num-executors * executor-cores的2~3倍較為合適
如果task數量偏少的話,Executor程式可能根本就沒有task執行,也就是白白浪費了資源

spark.storage.memoryFraction
設定RDD持久化資料在Executor記憶體中能佔的比例,預設是0.6
根據你選擇的不同的持久化策略,如果記憶體不夠時,可能資料就不會持久化,或者資料會寫入磁碟

如果Spark作業中,有較多的RDD持久化操作,該引數的值可以適當提高一些
如果Spark作業中的Shuffle類操作比較多,而持久化操作比較少,那麼這個引數的值適當降低一些比較合適
如果發現作業由於頻繁的GC導致執行緩慢(透過Spark WebUI可以觀察到作業的GC耗時),意味著Task執行使用者程式碼的記憶體不夠用,那麼同樣建議調低這個引數的值

spark.shuffle.memoryFraction
設定Shuffle過程中一個task拉取到上個Stage的Task的輸出後,進行聚合操作時能夠使用的Executor記憶體的比例,預設是0.2
Shuffle操作在進行聚合時,如果發現使用的記憶體超出了這個20%的限制,那麼多餘的資料就會溢寫到磁碟檔案中去,此時就會極大地降低效能

如果Spark作業中的RDD持久化操作較少,Shuffle操作較多時,建議降低持久化操作的記憶體佔比,提高Shuffle操作的記憶體佔比比例
如果發現作業由於頻繁的GC導致執行緩慢,意味著Task執行使用者程式碼的記憶體不夠用,那麼同樣建議調低這個引數的值



示例

#args : /usr/local/spark/bin/spark-submit --class Process --master yarn-cluster 
--name Process 
--queue fetech 
--num-executors 20 
--driver-memory 5g 
--executor-memory 4g 
--executor-cores 2 
--conf spark.default.parallelism=500 
--conf spark.storage.memoryFraction=0.5 
/process.jar $1 $2 $3 $4



作者:Alex90
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3407/viewspace-2818657/,如需轉載,請註明出處,否則將追究法律責任。

相關文章