Spark_Spark_RDD等_Shuffle調優_相關參數

 參考文章 : 

1.大數據技術之_19_Spark學習_07_Spark 性能調優 + 數據傾斜調優 + 運行資源調優 + 程序開發調優 + Shuffle 調優 + GC 調優 + Spark 企業應用案例

https://blog.csdn.net/u012990179/article/details/89812136

2.Spark 官方文檔,針對於Spark 表現性能的調優

http://spark.apache.org/docs/latest/configuration.html#shuffle-behavior

 

  之前一直沒有出相關的文章,這次整理一下。希望你看了這篇文章,作業的 task 不是200 個!!!

  首先 Shuffle 相關的參數與理解整個Shuffle 流程是密不可分的,建議在看這篇文章,如果你對整個Shuffle 流程還沒有一個直觀的認識,可以看下這篇文章。

https://blog.csdn.net/u010003835/article/details/106654789

 

基本資源調整

 

首先 ,Spark Shuffle 調優只是 Spark 中的一部分。並不是說通過調優,Spark 任務就會如何的快 。重要的是資源!!!

Spark 的資源在於以下幾個參數, 提交作業申請的 executor-num , executor-core, executor-memory 以及 driver-memory 

 

  • num-executors 

 – YARN-only
  參數說明:該參數用於設置 Spark 作業總共要用多少個 Executor 進程來執行。Driver 在向 YARN 集羣管理器申請資源時,YARN 集羣管理器會盡可能按照你的設置來在集羣的各個工作節點上,啓動相應數量的 Executor 進程。這個參數非常之重要,如果不設置的話,默認只會給你啓動少量的 Executor 進程,此時你的 Spark 作業的運行速度是非常慢的。
  參數調優建議:每個 Spark 作業的運行一般設置 50~100 個左右的 Executor 進程比較合適,設置太少或太多的 Executor 進程都不好。設置的太少,無法充分利用集羣資源;設置的太多的話,大部分隊列可能無法給予充分的資源。
 

  • executor-memory

  參數說明:該參數用於設置每個 Executor 進程的內存。Executor 內存的大小,很多時候直接決定了 Spark 作業的性能,而且跟常見的 JVM OOM 異常,也有直接的關聯。
  參數調優建議:每個 Executor 進程的內存設置 4G~8G 較爲合適。但是這只是一個參考值,具體的設置還是得根據不同部門的資源隊列來定。可以看看自己團隊的資源隊列的最大內存限制是多少,num-executors * executor-memory,是不能超過隊列的最大內存量的。此外,如果你是跟團隊裏其他人共享這個資源隊列,那麼申請的內存量最好不要超過資源隊列最大總內存的 1/3~1/2,避免你自己的 Spark 作業佔用了隊列所有的資源,導致別的同學的作業無法運行。
 

  • executor-cores

– Spark standalone and YARN only
  參數說明:該參數用於設置每個 Executor 進程的 CPU core 數量。這個參數決定了每個 Executor 進程並行執行 task 線程的能力。因爲每個 CPU core 同一時間只能執行一個 task 線程,因此每個 Executor 進程的 CPU core 數量越多,越能夠快速地執行完分配給自己的所有 task 線程。
  參數調優建議:Executor 的 CPU core 數量設置爲 2~4 個較爲合適。同樣得根據不同部門的資源隊列來定,可以看看自己的資源隊列的最大 CPU core 限制是多少,再依據設置的 Executor 數量,來決定每個 Executor 進程可以分配到幾個 CPU core。同樣建議,如果是跟他人共享這個隊列,那麼 num-executors * executor-cores 不要超過隊列總 CPU core 的 1/3~1/2 左右比較合適,也是避免影響其他同學的作業運行。
 

  • spark.default.parallelism

注意: 這個參數一定要做調整,否則很可能出現 task 沒數據的情況 !!! 有些同學講調優,但是這個參數都不做調整 。。。

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

  • spark.storage.memoryFraction (deprecated)

  參數說明:該參數用於設置 RDD 持久化數據在 Executor 內存中能佔的比例,默認是 0.6。也就是說,默認 Executor 60% 的內存,可以用來保存持久化的 RDD 數據。根據你選擇的不同的持久化策略,如果內存不夠時,可能數據就不會持久化,或者數據會寫入磁盤。
  參數調優建議:如果 Spark 作業中,有較多的 RDD 持久化操作,該參數的值可以適當提高一些,保證持久化的數據能夠容納在內存中。避免內存不夠緩存所有的數據,導致數據只能寫入磁盤中,降低了性能。但是如果 Spark 作業中的 shuffle 類操作比較多,而持久化操作比較少,那麼這個參數的值適當降低一些比較合適。此外,如果發現作業由於頻繁的 gc 導致運行緩慢(通過 spark web ui 可以觀察到作業的 gc 消耗),意味着 task 執行用戶代碼的內存不夠用,那麼同樣建議調低這個參數的值。

 

 

  • spark.shuffle.memoryFraction (deprecated)

  參數說明:該參數用於設置 shuffle 過程中一個 task 拉取到上個 stage 的 task 的輸出後,進行聚合操作時能夠使用的 Executor 內存的比例,默認是 0.2。也就是說,Executor 默認只有 20% 的內存用來進行該操作。shuffle 操作在進行聚合時,如果發現使用的內存超出了這個 20% 的限制,那麼多餘的數據就會溢寫到磁盤文件中去,此時就會極大地降低性能。
  參數調優建議:如果 Spark 作業中的 RDD 持久化操作較少,shuffle 操作較多時,建議降低持久化操作的內存佔比,提高 shuffle 操作的內存佔比比例,避免 shuffle 過程中數據過多時內存不夠用,必須溢寫到磁盤上,降低了性能。此外,如果發現作業由於頻繁的 g c導致運行緩慢,意味着 task 執行用戶代碼的內存不夠用,那麼同樣建議調低這個參數的值。
 

額外 :

1)Spark 目前也支持了 Off-heap memory, 默認是不開啓的,Off-heap 繞過了JVM 的垃圾回收機制,排除了 Full GC 影響。

2) spark.storage.memoryFraction (deprecated)  與  spark.shuffle.memoryFraction (deprecated)  是老版本 Spark 1.5 及之前的版本的固定內存參數進行設置的。如果讓這些內存參數生效 spark.memory.useLegacyMode 需要設置爲 true

    1.6+ 的浮動內存管理版本,初始比例由  spark.memory.fraction 進行確定, Fraction of (heap space - 300MB) used for execution (中間數據含Shuffle 數據)  and storage.

 

最新文檔

http://spark.apache.org/docs/latest/configuration.html#memory-management

 

小結 :

     資源參數的調優,沒有一個固定的值,需要同學們根據自己的實際情況(包括 Spark 作業中的 shuffle 操作數量、RDD 持久化操作數量以及 spark web ui 中顯示的作業 gc 情況),同時參考本篇文章中給出的原理以及調優建議,合理地設置上述參數。
  一個 CPU core 同一時間只能執行一個線程。而每個 Executor 進程上分配到的多個 task,都是以每個 task 一條線程的方式,多線程併發運行的。
  一個應用提交的時候設置多大的內存?設置多少 Core?設置幾個 Executor?
 

參考作業資源申請:

以下是一份 spark-submit 命令的示例,大家可以參考一下,並根據自己的實際情況進行調節

./bin/spark-submit \
--master yarn-cluster \
--num-executors 100 \
--executor-memory 6G \
--executor-cores 4 \
--driver-memory 1G \
--conf spark.default.parallelism=1000 \
--conf spark.storage.memoryFraction=0.5 \
--conf spark.shuffle.memoryFraction=0.3 \

 

 

Spark Shuffle 參數調整

  下面我們看下 Spark Shuffle 的一些調整參數

 以下是 Shuffle 過程中的一些主要參數,這裏詳細講解了各個參數的功能、默認值以及基於實踐經驗給出的調優建議。

 

完整的參數說明 :

http://spark.apache.org/docs/latest/configuration.html#shuffle-behavior

 

  • spark.shuffle.file.buffer

  默認值:32k
  參數說明:該參數用於設置 shuffle write task 的 BufferedOutputStream 的 buffer 緩衝大小。將數據寫到磁盤文件之前,會先寫入 buffer 緩衝中,待緩衝寫滿之後,纔會溢寫到磁盤。
  調優建議:如果作業可用的內存資源較爲充足的話,可以適當增加這個參數的大小(比如 64k),從而減少 shuffle write 過程中溢寫磁盤文件的次數,也就可以減少磁盤 IO 次數,進而提升性能。在實踐中發現,合理調節該參數,性能會有 1%~5% 的提升。

 

  • spark.reducer.maxSizeInFlight

  默認值:48m
  參數說明:該參數用於設置 shuffle read task 的 buffer 緩衝大小,而這個 buffer 緩衝決定了每次能夠拉取多少數據。
  調優建議:如果作業可用的內存資源較爲充足的話,可以適當增加這個參數的大小(比如 96m),從而減少拉取數據的次數,也就可以減少網絡傳輸的次數,進而提升性能。在實踐中發現,合理調節該參數,性能會有 1%~5% 的提升。

 

  • spark.shuffle.sort.bypassMergeThreshold

  默認值:200
  參數說明:當 ShuffleManager 爲 SortShuffleManager 時,如果 shuffle read task 的數量小於這個閾值(默認是 200),則 shuffle write 過程中不會進行排序操作,而是直接按照未經優化的 HashShuffleManager 的方式去寫數據,但是最後會將每個 task 產生的所有臨時磁盤文件都合併成一個文件,並會創建單獨的索引文件。
  調優建議:當你使用 SortShuffleManager 時,如果的確不需要排序操作,那麼建議將這個參數調大一些,大於 shuffle read task 的數量。那麼此時就會自動啓用 bypass 機制,map-side 就不會進行排序了,減少了排序的性能開銷。但是這種方式下,依然會產生大量的磁盤文件,因此 shuffle write 性能有待提高。

 

  • spark.shuffle.io.maxRetries

  默認值:3
  參數說明:shuffle read task 從 shuffle write task 所在節點拉取屬於自己的數據時,如果因爲網絡異常導致拉取失敗,是會自動進行重試的。該參數就代表了可以重試的最大次數。如果在指定次數之內拉取還是沒有成功,就可能會導致作業執行失敗。
  調優建議:對於那些包含了特別耗時的 shuffle 操作的作業,建議增加重試最大次數(比如 60 次),以避免由於 JVM 的 full gc 或者網絡不穩定等因素導致的數據拉取失敗。在實踐中發現,對於針對超大數據量(數十億~上百億)的 shuffle 過程,調節該參數可以大幅度提升穩定性。

spark.shuffle.io.retryWait
  默認值:5s
  參數說明:具體解釋同上,該參數代表了每次重試拉取數據的等待間隔,默認是 5s。
  調優建議:建議加大間隔時長(比如 60s),以增加 shuffle 操作的穩定性。

 

  • spark.shuffle.manager  

廢棄  Spark2.0 +移除了 hash 

 Spark 2.4.5 已經移除了 Hash Shuffle !!!
  默認值:sort
  參數說明:該參數用於設置 ShuffleManager 的類型。Spark 1.5 以後,有三個可選項:hash、sort 和 tungsten-sort。HashShuffleManager 是 Spark 1.2 以前的默認選項,但是 Spark 1.2 以及之後的版本默認都是 SortShuffleManager 了。tungsten-sort 與 sort 類似,但是使用了 tungsten 計劃中的堆外內存管理機制,內存使用效率更高。
  調優建議:由於 SortShuffleManager 默認會對數據進行排序,因此如果你的業務邏輯中需要該排序機制的話,則使用默認的 SortShuffleManager 就可以;而如果你的業務邏輯不需要對數據進行排序,那麼建議參考後面的幾個參數調優,通過 bypass 機制或優化的 HashShuffleManager 來避免排序操作,同時提供較好的磁盤讀寫性能。這裏要注意的是,tungsten-sort 要慎用,因爲之前發現了一些相應的 bug。


 

 

頻繁 GC 或者 OOM


針對這種情況,首先要確定現象是發生在 Driver 端還是在 Executor 端,然後在分別處理。
Driver 端:通常由於計算過大的結果集被回收到 Driver 端導致,需要調大 Driver 端的內存解決,或者進一步減少結果集的數量。
Executor 端:
  (1)以外部數據作爲輸入的 Stage:這類 Stage 中出現 GC 通常是因爲在 Map 側進行 map-side-combine 時,由於 group 過多引起的。解決方法可以增加 partition 的數量(即 task 的數量)來減少每個 task 要處理的數據,來減少 GC 的可能性。
  (2)以 shuffle 作爲輸入的 Stage:這類 Stage 中出現 GC 的通常原因也是和 shuffle 有關,常見原因是某一個或多個 group 的數據過多,也就是所謂的數據傾斜,最簡單的辦法就是增加 shuffle 的 task 數量,比如在 SparkSQL 中設置 SET spark.sql.shuffle.partitions=400,如果調大 shuffle 的 task 無法解決問題,說明你的數據傾斜很嚴重,某一個 group 的數據遠遠大於其他的 group,需要你在業務邏輯上進行調整,預先針對較大的 group 做單獨處理。
 

 

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