[spark性能調優]spark submit資源參數調優及amazon集羣示例

目錄

一、spark作業基本運行原理

二、資源參數調優

Spark內存管理:

三、amazon集羣資源參數示例


 

一、spark作業基本運行原理

資源申請與分配:

       我們使用spark-submit提交一個spark作業後,這個作業會啓動一個對應的Driver進程。根據使用的部署模式(deploy-mode)不同,Driver進程可能在本地啓動(client mode),也可能在集羣中某個工作節點啓動(cluster mode)。Driver進程本身根據我們設置的參數,佔有一定數量的內存和CPU core。而Driver進程要做的第一件事情,就是向集羣管理器YARN申請運行spark作業需要使用的資源,這裏的資源指的就是executor進程。YARN集羣管理器會根據我們爲spark作業設置的資源參數,在各個工作節點上,啓動一定數量的executor進程,每個executor進程都佔有一定數量的內存和CPU core。

Task分配:

       在申請到作業執行所需的資源後,Driver進程就會開始調度和執行我們編寫的作業代碼了。Driver進程會將我們編寫的spark作業代碼分拆爲多個stage,每個stage執行一部分代碼片段,併爲每個stage創建一批task,然後將這些task分配到各個executor進程中執行。Task是最小的計算單元,負責執行一模一樣的計算邏輯(也就是我們自己編寫的某個代碼片段),只是每個task處理的數據不同而已。一個stage的所有task都執行完畢之後,會在各個節點本地的磁盤文件中寫入計算中間結果,然後driver就會調度運行下一個stage。下一個stage的輸入數據就是上一個stage輸出的中間結果。如此循環往復,直到將我們自己編寫的代碼邏輯全部執行完,並且計算完所有的數據,得到我們想要的結果爲止。

       Spark是根據shuffle類算子來進行stage的劃分。如果我們的代碼中執行了某個shuffle類算子(比如reduceByKey、join等),那麼就會在該算子處,劃分出一個stage界限來。可以大致理解爲,shuffle算子執行之前的代碼會被劃分爲一個stage,shuffle算子執行以及之後的代碼會被劃分爲下一個stage。因此一個stage剛開始執行時,每個task會從上一個stage的task所在的節點,去通過網絡傳輸拉取需要自己處理的所有key,然後對拉取到的所有相同key使用我們自己編寫的算子函數執行聚合操作(比如reduceBykey算子接收的函數)。這個過程就是shuffle。

Executor內存和CPU core

       當我們在代碼中執行了cache/persist等持久化操作時,根據我們選擇的持久化級別的不同,每個task計算出的數據也會保存到executor進程的內存或所在節點的磁盤文件中。

       Executor的內存主要分爲三塊:第一塊是讓task執行我們自己編寫的代碼時使用,默認是佔executor總內存的20%;第二塊是讓task通過shuffle過程拉取上一個stage的task輸出後,進行聚合等操作時使用,默認佔executor總內存的20%;第三塊是數據持久化時使用的,默認佔executor總內存的60%。

      Task的執行速度是跟每個executor進程的CPU core數量有直接關係的。一個cup core 同一時間只能執行一個線程。而每個executor進程上分配到多個task,都是以每個task一條線程的方式,多線程併發運行的。如果CPUcore數量比較充足,而且分配到的task數量比較合理,那麼通常來說,可以比較快速和高效地執行完這些task線程。

二、資源參數調優

Driver-memory

  • 參數說明:改參數用於設置Driver進程的內存。
  • 參數調優建議:Driver的內存通常來說設置爲1G。Driver負責任務的調度,和executor、AM之間的消息通信,當任務數變多,任務平行度增大時,Driver內存需要相應增大,否則會由於內存不足,導致進程之間通信斷裂問題。還需要注意的是,如果需要使用collect算子將數據全部拉取到Driver上進行處理,那麼必須確保Driver的內存足夠大,否則會出現OOM內存溢出的問題。

Num-executors

  • 參數說明:該參數用於設置集羣的各個工作節點上啓動executor的數量。
  • 參數調優建議:每個spark作業的運行一般設置50~100個左右的executor進程比較合適。設置的太少,無法充分利用集羣資源;設置的太多,大部分隊列可能無法給予充分的資源。

Executor-cores

  • 參數說明:該參數用於設置每個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比較合適,避免影響其他同學的作業運行。

Executor-memory

  • 參數說明:該參數用於設置每個executor進程的內存。Executor內存的大小,很多時候直接決定了spark作業的性能,而且跟常見的JVM OOM異常,也有直接的關聯。
  • 參數調優建議:每個executor進程的內存設置爲4G~8G較爲合適,但這只是一個參考值,具體設置還是根據資源隊列來定。Num-executors * executor-memory,是不能超過隊列的最大內存量。

Spark.default.parallelism

  • 參數說明:該參數用於設置每個stage的默認task數量。
    • 參數調優建議:spark作業的默認task數量爲500~1000個較爲合適。如果這個參數不設置,那麼此時就會導致spark根據底層HDFS的block數量來設置task數量,默認一個HDFS block對應一個task。通常來說,spark默認設置的數量是偏少的,如果task數量偏少的話,就會導致前面設置好的executor參數都前功盡棄。試想一下,無論executor進程有多少個,內存和CPU有多大,但是task只有1個或者10個,90%的executor進程可能根本就沒有task執行,也就是白白浪費資源。Spark官網建議的原則是,設置該參數爲num-executors*executor-core的2~3倍較爲合適,此時可以充分利用spark集羣資源

Spark.storage.memoryFraction(Before spark 1.6)

  • 參數說明:該參數用於設置持久化數據在executor內存中能佔的比例,默認爲0.6。根據選擇的不同的持久化策略,如果內存不夠時,可能數據就不會持久化,或者數據寫入硬盤。
  • 參數調優建議:如果spark作業中,有較多的持久化操作,該參數的值可以適當提高一些,保證持久化的數據能夠容納在內存中。必滿內存不夠緩存所有數據,導致數據只能寫入磁盤中,降低了性能。此外,如果發現作業由於頻繁的gc導致運行緩慢,意味着task執行用戶代碼的內存不足,同樣建議調低這個參數值。

Spark.shuffle.memoryFraction(Before spark 1.6)

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

spark.memory.fraction (After spark 1.6)

  • 參數說明:該參數用於設置execution和storage數據在executor內存中能佔的比例,默認0.75。
  • 參數調優建議:該參數設置過小,內存不夠用,會導致數據溢寫到磁盤,降低性能。同時發現作業由於頻繁的gc導致運行緩慢,意味着task執行用戶代碼的內存不夠用,建議調低該參數。

Spark.memory.storageFraction(After spark 1.6)

  • 參數說明:該參數用於設置spark.memory.fraction中storage內存佔比,默認0.5。
  • 參數調優建議:在spark1.6之後的版本中,storage memory和execution memory可以互借,如果storage memory的空間已經超過了設定的大小,execution向storage借用內存時,storage memory只能釋放出超過設定的空間給execution。

Spark內存管理:

Before 1.6

      對於一個executor,內存由以下三個部分組成:(spark1.6之後的版本,需要設置spark.memory.useLegacyMode=true,下面參數配置才起作用)

      Execution memory:這片區域是爲了解決shuffles,joins,sorts and aggregations過程中爲了避免頻繁IO需要的buffer。通過spark.shuffle.memoryFraction配置,默認0.2。

     Storage memory:這邊區域是爲了解決block cache(cache\persist方法),broadcast,以及task results的存儲。可以通過spark.storage.memoryFraction設置,默認0.6。

     Other memory:給系統預留,因爲程序本身運行也是需要內存的,默認0.2。

     這種內存分配機制最大的問題是,每塊內存的使用都不能超過各自的上限,即使另外一塊內存空閒,仍不可被其他部分使用

After 1.6

Executor 中的內存分爲兩部分:

       User memory:給系統預留,因爲程序本身運行也是需要內存的,默認0.25。

   Spark memory:這部分內存包含storage memory 和 execution memory兩部分,這兩部分邊界由spark.memory.storageFraction參數設置,默認爲0.5,新內存管理模型中的優點是,這個邊界不是固定的,如果一個區域內存不夠用時,可以從另一區域借用。Execution memory保存的是用來計算的中間結果,如果計算過程中找不到存儲的數據,會導致任務失敗,因而這部分內存的blocks不會被其他線程的task擠出去。Storage memory 緩存內存中數據,如果數據被驅逐,要想再拿到這些數據時,重新計算就可以。Execution向storage借用空間時,有兩種可能:一種,storage memory有空閒空間,可以直接增大execution大小,減小storage memory大小;另一種,storage memory空間已經超過設定的大小,強制將storage memory釋放超過設定值的部分空間,還給execution memory。反之亦然,只是execution memory 佔用的空間不可釋放,借給storage memory使用。

三、amazon集羣資源參數示例

以m4.xlarge實例爲例,首先查詢各個工作節點最大可使用的CPU和內存資源,/etc/hadoop/conf/yarn-site.xml

  <property>
    <name>yarn.nodemanager.resource.cpu-vcores</name>
    <value>4</value>
  </property>
  <property>
    <name>yarn.nodemanager.resource.memory-mb</name>
    <value>12288</value>
  </property>

資源分配滿足最大資源限制:

Executor-num * executor-cores <= 4

Executor-num * executor-memory <= 12g

根據作業具體情況設置資源參數如下:

--driver-memory 2G      //driver memory 設置太小,會出現OOM問題,導致任務失敗
--executor-memory 10G 
--executor-cores 4  
--num-executors 1
--conf spark.default.parallelism=200  // nodes-num * executor-num * executor-cores * (2/3)
--conf spark.memory.fraction=0.6   //根據GC 時間調整
--conf spark.memory.storageFraction=0.5   //設定的內存值:heap-reserved memory * 0.6 * 0.5

 

 

參考資料:

 

https://tech.meituan.com/spark_tuning_basic.html

https://blog.csdn.net/Full_Stack_delp/article/details/72878236

https://www.cnblogs.com/dreamfly2016/p/5720526.html

https://amazonaws-china.com/cn/blogs/big-data/submitting-user-applications-with-spark-submit/

 

 

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