運行在YARN上的Spark程序的Executor,Cores和Memory的分配

在跑Spark-On-Yarn程序的時候,往往會對幾個參數(num-executors,executor-cores,executor-memory等)理解很模糊,從而憑感覺地去指定值,這是不符合有追求程序員信仰的。因此,搞懂它們,很有必要。
本文翻譯自https://spoddutur.github.io/spark-notes/distribution_of_executors_cores_and_memory_for_spark_application.html

譯文如下:

是否曾經想要知道如何根據你的集羣,配置這些Spark運行參數:--num-executors, --executor-memory and --execuor-cores 呢?

探究思路

  1. 理論引導:首先,有必要了解一些重要建議,能幫助我們更好地理解它;
  2. 實戰:其次,以一個集羣爲例,推演出該集羣的參數的推薦值。

理論引導

當配置參數時,請遵循下表,將其推薦建議牢記於心

  • Hadoop/Yarn/OS 守護進程:
    當利用一個集羣管理器(比如YARN)運行spark程序時,存在一些守護進程運行在後臺,比如NameNode,Secondary NameNode,DataNode,JobTracker和TaskTracker。因此,當確定num-executor時,我們需要確保有足夠的cores(大約每個節點一個core)維持這些守護進程的平穩運行。
  • Yarn ApplicationMaster (AM):
    ApplicationMaster的職責是:向ResourceManager協商資源,與NodeManager一同執行並監控containner及其資源消耗。如果程序運行在Spark-On-Yarn,我們需要預留一些資源給ApplicationMaster,AM大約需要1024MB的內存和一個Executor。
  • HDFS吞吐:
    HDFS客戶端會遇到大量併發線程的問題。 據觀察,HDFS當達到全寫入吞吐量時,需要每個executor執行約5個任務。 因此,最好控制每個executor中core的數目低於那個數字。
  • 內存開銷:
    下圖描繪了spark-yarn的內存使用情況:
    [圖片上傳失敗...(image-fa6806-1536392056623)]
    圖中注意兩件事情:
       Full memory requested to yarn per executor =
          spark-executor-memory + spark.yarn.executor.memoryOverhead
      spark.yarn.executor.memoryOverhead = 
            Max(384MB, 7% of spark.executor-memory)

所以,如果我們申請了每個executor的內存爲20G時,對我們而言,AM將實際得到20G+ memoryOverhead = 20 + 7% * 20GB = ~23G內存。

  • 執行擁有太多內存的executor會產生過多的垃圾回收延遲
  • 執行過小的executor(舉例而言,一個只有一核和僅僅足夠內存跑一個task的executor),將會丟失在單個JVM中運行多任務的好處。

理論夠了...開始實戰

現在,我們考慮一個10個節點的如下配置的集羣,並分析不同參數設置的結果。
集羣配置如下:

**集羣配置:**
10個節點
每個節點16核
每個節點64G內存

第一種方案:Tiny executors [每個Executor一個Core]

Tiny executors表示一個executor配置一個core。下表描述了該方案下的參數配置。

- '--num-executors' = '該方案下,每個executor配置一個core'
                                = '集羣中的core的總數'
                                = '每個節點的core數目 * 集羣中的節點數' 
                                = 16 x 10 = 160
- '--executor-cores' = 1 (每個executor一個core)
- '--executor-memory' = '每個executor的內存'
                                    = '每個節點的內存/每個節點的executor數目'
                                    = 64GB/16 = 4GB

分析:當一個executor只有一個core時,正如我們上面分析的,我們可能不能發揮在單個JVM上運行多任務的優勢。此外,共享/緩存變量(如廣播變量和累加器)將複製到節點的每個core,這裏是16次。並且,我們沒有爲Hadoop / Yarn守護進程留下足夠的內存開銷,我們也沒有計入ApplicationManager。因此,這不是一個好的方案!

第二種方案:Fat executors (每個節點一個Executor):

Fat executors表示一個executor獨佔一個節點。下表描述了該方案下的參數配置:

- `--num-executors` = `該方案下,一個executor獨佔一個節點`
                                = `集羣中的節點的數目`
                                = 10
- `--executor-cores` = `一個節點一個executor意味着每個executor獨佔節點中所 
                                   有的cores`
                                = `節點中的core的數目`
                                = 16
- `--executor-memory` = `每個executor的內存`
                                    = `節點的內存/節點中executor的數目`
                                    = 64GB/1 = 64GB

分析:每個executor獨佔16個核心,則ApplicationManager和守護程序進程則無法分配到core,並且,HDFS吞吐量會受到影響,導致過多的垃圾結果。 同樣地,該方案不好!

第三種方案:Balance between Fat (vs) Tiny

根據上面討論的建議:

  • 基於上述的建議,我們給每個executor分配5個core => -- executor-cores = 5 (保證良好的HDFS吞吐)
  • 每個節點留一個core給Hadoop/Yarn守護進程 => 每個節點可用的core的數目 = 16 - 1
  • 所以,集羣中總共可用的core的數目是 15 * 10 = 150
  • 可用的executor的數目 = (總的可用的core的數目 / 每個executor的core的數目)= 150 / 5 = 30
  • 留一個executor給ApplicationManager => --num-executors = 29
  • 每個節點的executor的數目 = 30 / 10 = 3
  • 每個executor的內存 = 64GB / 3 = 21GB
  • 計算堆開銷 = 7% * 21GB = 3GB。因此,實際的 --executor-memory = 21 - 3 = 18GB

因此,推薦的配置如下:29 executors, 18GB memory each and 5 cores

each !
分析:很明顯,第三種方案在Fat vs Tiny 兩種方案中找到了合適的平衡點。毋庸置疑,它實現了Fat executor的並行性和Tiny executor的最佳吞吐量!

結論:

我們看到:

  • 當爲spark程序配置運行參數的時候,應謹記一些推薦事項:
    1.爲Yarn的Application Manager預留資源
    2.我們應該如何爲Hadoop / Yarn / OS deamon進程節省一些cores
    3.學習關於spark-yarn-memory-usage
  • 另外,檢查並分析了配置這些參數的三種不同方法:
    1.Tiny Executors - 每個executor配置一個core
    2.Fat Executors - 每個executor獨佔一個節點
    3.推薦方案 - 基於建議項的Tiny(Vs)Fat的合適的平衡。

--num-executors, --executor-cores and --executor-memory..這三個參數在spark性能中扮演很重要的角色,他們控制這你的spark程序獲得的CPU和內存的資源。對於用戶來說,很有必要理解如何去配置它們。希望這篇博客對你有幫助。

 

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