Spark之如何設置Spark資源


資源影響因素

Spark和Yarn管理的資源限制因素:

  • CPU
  • 內存
  • 磁盤
  • 網絡I/O

Spark和Yarn管理的兩個主要資源為CPU和內存,剩下不會主動管理,所以設置資源也是主要通過這兩方面進行設置。

資源優化配置

  在資源配置中,可以用過代碼的設置sparkconf進行設置,或者在腳本里通過參數進行設置,腳本的優先級大於代碼的優先級。YARN的相關屬性是

# 控制每個節點上的容器使用的最大內存總和。
yarn.nodemanager.resource.memory-mb
# 控制每個節點上的容器使用的最大內核總數。
yarn.nodemanager.resource.cpu-vcores 

  YARN請求的內存時,需要注意一下兩點:

  • --executor-memory/spark.executor.memory 控制執行程序堆的大小,但是JVM也可以在堆外使用一些內存,例如,spark.yarn.executor.memoryOverhead 用於內聯的String和直接字節緩沖區。屬性的值將添加到執行程序內存中,以確定每個執行程序對YARN的完整內存請求。默認為max(384,.07 * spark.executor.memory)。 
  •  YARN可能會將請求的內存向上舍入一點。YARN 和屬性分別控制最小和增量請求值。yarn.scheduler.minimum-allocation-mbyarn.scheduler.increment-allocation-mb

在確定Spark執行程序的大小時要注意的最后幾個問題:

  • 應用程序主服務器是一個非執行程序容器,具有從YARN請求容器的特殊功能,它占用必須自己預算的資源。在yarn-client模式下,它默認為1024MB和一個vcore。yarn-cluster模式下,應用程序主控程序運行驅動程序,因此使用屬性支持其資源通常很有用--driver-memory--driver-cores
  • 運行內存過多的執行程序通常會導致過多的垃圾回收延遲(當內存不足時會觸發JVM回收內存)。對於單個執行器來說,64GB是一個不錯的上限。
  • executor遇到大量並發線程效率會降低。官方的建議是,每個executor最多可以設置五個task,以實現較高效率的寫入吞吐量,因此最好將每個executor的vcores保持在該數量以下。
  • 啟動太多executor執行比較少任務的時候,會拋棄同個executor起多線程的效率,反而降低效率。例如,廣播變量需要在每個executor上復制一次,因此太多executor將產生更多的副本成本。

腳本模板

./spark-submit \
--class 入口類
--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 \
jar包路徑 參數

num-executors

  參數說明:該參數用於設置Spark作業總共要用多少個Executor進程來執行。Driver在向YARN集群管理器申請資源時,YARN集群管理器會盡可能按照你的設置來在集群的各個工作節點上,啟動相應數量的Executor進程。不設置默認值是2。

  參數調優建議:根據從節點的數據量設置對應的數量,設置太多會讓一台節點起多個executor,影響機器的性能,起太少會讓節點空閑。

executor-memory

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

  參數調優建議:具體情況得根據不同部門的資源隊列和程序部署的情況來決定,數據源大小也是一個參考點;但num-executors * executor-memory,是不能超過隊列的最大內存量的。此外,如果資源是和別人共享的情況或者多程序的情況,那么申請的內存量最好不要超過資源隊列最大總內存的1/3~1/2,避免你自己的Spark作業占用了隊列所有的資源,導致別的同事的作業無法運行。

 executor-cores

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

  參數調優建議:每個Executor同時執行5個task時HDFS的寫的吞吐量是最好的。所以,建議將executor-cores的值為3-5。這個限制也要根據資源情況來限定,例如資源隊列里最大的CPU core數量,假設你的executor的內存沒辦法配置太大,那么executor-cores不能配置太多,不然會導致內存不夠而引起內存溢出。

driver-memory

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

  參數調優建議:Driver的內存通常來說不設置,或者設置1G左右應該就夠了。但你的程序有使用collect算子將RDD的數據全部拉取到Driver上進行處理(或者是用map side join操作),那么必須確保Driver的內存足夠大,否則會出現OOM內存溢出的問題。

spark.default.parallelism

  參數說明:該參數用於設置每個stage的默認task數量,也可以認為是分區數。

  參數調優建議:Spark官網的建議是,設置該參數為num-executors * executor-cores的2~3倍較為合適;如果不設置這個參數,那么會導致Spark自己根據底層HDFS的block數量來設置task的數量,默認是一個HDFS block對應一個task。通常來說,Spark默認設置的數量是偏少的(比如就幾十個task),如果task數量偏少的話,就會導致你前面設置好的Executor的cpu閑置,浪費資源。

spark.storage.memoryFraction

  參數說明:該參數用於設置RDD持久化數據在Executor內存中能占的比例,默認是0.6。也就是說,默認Executor 60%的內存,可以用來保存持久化的RDD數據。根據你選擇的不同的持久化策略,如果內存不夠時,可能數據就不會持久化,或者數據會寫入磁盤。

  參數調優建議:如果Spark作業中,有較多的RDD持久化操作,該參數的值可以適當提高一些,保證持久化的數據能夠容納在內存中。避免內存不夠緩存所有的數據,導致數據只能寫入磁盤中,降低了性能。但是如果Spark作業中的shuffle類操作比較多,而持久化操作比較少,那么這個參數的值適當降低一些比較合適。此外,如果發現作業由於頻繁的gc導致運行緩慢(通過spark web ui可以觀察到作業的gc耗時),意味着task執行用戶代碼的內存不夠用,那么同樣建議調低這個參數的值。

 spark.shuffle.memoryFraction

  參數說明:該參數用於設置shuffle過程中一個task拉取到上個stage的task的輸出后,進行聚合操作時能夠使用的Executor內存的比例,默認是0.2。也就是說,Executor默認只有20%的內存用來進行該操作。shuffle操作在進行聚合時,如果發現使用的內存超出了這個20%的限制,那么多余的數據就會溢寫到磁盤文件中去,此時就會極大地降低性能。

  參數調優建議:如果Spark作業中的RDD持久化操作較少,shuffle操作較多時,建議降低持久化操作的內存占比,提高shuffle操作的內存占比比例,避免shuffle過程中數據過多時內存不夠用,必須溢寫到磁盤上,降低了性能。此外,如果發現作業由於頻繁的gc導致運行緩慢,意味着task執行用戶代碼的內存不夠用,那么同樣建議調低這個參數的值。

配置參數

假設集群服務器配置:

節點:10
核數:16/台
內存:64GB/台

配置一:使用較小的executors

  這里起和核數相同的executor

--num-executors =  16 x 10 = 160
--executor-cores = 1 (one executor per core)
--executor-memory = `mem-per-node/num-executors-per-node`
                     = 64GB/16 = 4GB

  由於每個executor只分配了一個核,我們將無法利用在同一個JVM中運行多個任務的優點。 此外,共享/緩存變量(如廣播變量和累加器)將在節點的每個核心中復制16次。 最嚴重的就是,我們沒有為Hadoop / Yarn守護程序進程留下足夠的內存開銷,我們還忘記了將ApplicationManagers運行所需要的開銷加入計算。

配置二:使用較大的executors

  每個executor都有16個核

--num-executors =  10
--executor-cores = 16 
--executor-memory = `mem-per-node/num-executors-per-node`
                     = 64GB/1 = 64GB

  由於HDFS客戶端遇到大量並發線程會出現一些bug,即HDFS吞吐量會受到影響。同時過大的內存分配也會導致過多的GC延遲。

配置三:使用優化的executors

--num-executors =  29
--executor-cores = 5 
--executor-memory = 19GB

(1)給每個Executor分配5個core即executor-cores=5,這樣對HDFS的吞吐量會比較友好。
(2)為后台進程留一個core,則每個節點可用的core數是16 - 1 = 15。所以集群總的可用core數是15 x 10 = 150
(3)每個節點上的Executor數就是 15 / 5 = 3,集群總的可用的Executor數就是 3 * 10 = 30 。為ApplicationManager留一個Executor,則num-executors=29
(4)每個節點上每個Executor可分配的內存是 (64GB-1GB) / 3 = 21GB(減去的1GB是留給后台程序用),除去MemoryOverHead=max(384MB, 7% * 21GB)=2GB,所以executor-memory=21GB - 2GB = 19GB
 此方法既保證了在一個JVM實例里能同時執行task的優勢,也保證了hdfs的吞吐量。

配置四:在配置三基礎上再優化

  按照方法三,每個Executor分配到的內存是19GB,假設10GB內存就夠用了。那么此時我們可以將executor-cores降低如降低為3,那么每個節點就可以有15 / 3 = 5個Executor,那么總共可以獲得的Executor數就是 (5 * 10) - 1 =49,每個節點上每個Executor可分配的內存是(64GB-1GB) / 5 = 12GB,除去
MemoryOverHead=max(384MB, 7% * 12GB)=1GB,所以executor-memory=12GB - 1GB = 11GB
所以最后的參數配置是

--num-executors =  49
--executor-cores = 3 
--executor-memory = 11GB

  這里只是做一個參考,具體的實際情況依照個人的資源情況,參考有數據量大小,部門的資源使用情況等。一切以實際為准,這里只是搬運整理下資源以便翻閱。

參考博客:https://www.cnblogs.com/arachis/p/spark_parameters.html  http://www.dzjqx.cn/news/show-28638.html https://blog.cloudera.com/how-to-tune-your-apache-spark-jobs-part-2/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM