spark內存分配


問題描述

在測試spark on yarn時,發現一些內存分配上的問題,具體如下。

在$SPARK_HOME/conf/spark-env.sh中配置如下參數:

SPARK_EXECUTOR_INSTANCES=4 在yarn集群中啟動的executor進程數

SPARK_EXECUTOR_MEMORY=2G 為每個executor進程分配的內存大小

SPARK_DRIVER_MEMORY=1G 為spark-driver進程分配的內存大小

執行$SPARK_HOME/bin/spark-sql –master yarn,按yarn-client模式啟動spark-sql交互命令行(即driver程序運行在本地,而非yarn的container中),日志顯示的關於AppMaster和Executor的內存信息如下:
這里寫圖片描述
這里寫圖片描述

日志顯示,AppMaster的內存是896MB,其中包含了384MB的memoryOverhead;啟動了5個executor,第一個的可用內存是530.3MB,其余每個Executor的可用內存是1060.3MB。

到yarnUI看下資源使用情況,共啟動了5個container,占用內存13G,其中一台NodeManager啟動了2個container,占用內存4G(1個AppMaster占1G、另一個占3G),另外3台各啟了1個container,每個占用3G內存。
這里寫圖片描述

再到sparkUI看下executors的情況,這里有5個executor,其中driver是運行在執行spark-sql命令的本地服務器上,另外4個是運行在yarn集群中。Driver的可用storage memory為530.3MB,另外4個都是1060.3MB(與日志信息一致)。
這里寫圖片描述

那么問題來了:

  1. Yarn為container分配的最小內存由yarn.scheduler.minimum-allocation-mb參數決定,默認是1G,從yarnUI中看確實如此,可為何spark的日志里顯示AppMaster的實際內存是896-384=512MB呢?384MB是怎么算出來的?

  2. spark配置文件里指定了每個executor的內存為2G,為何日志和sparkUI上顯示的是1060.3MB?

  3. driver的內存配置為1G,為何sparkUI里顯示的是530.3MB呢?

  4. 為何yarn中每個container分配的內存是3G,而不是executor需要的2G呢?

問題解析

進過一番調研,發現這里有些概念容易混淆,整理如下,序號對應上面的問題:

  1. spark的yarn-client向ResourceManager申請提交作業/啟動AppMaster時,會判斷是否是集群模式,如果是集群模式,則AppMaster的內存大小與driver內存大小一致,否則由spark.yarn.am.memory決定,這個參數的默認值是512MB。我們使用的是yarn-client模式,所以實際內存是512MB。

384MB是spark-client為appMaster額外申請的內存,計算方法如下:
這里寫圖片描述

即,默認從參數讀取(集群模式從spark.yarn.driver.memoryOverhead參數讀,否則從spark.yarn.am.memoryOverhead參數讀),若沒配此參數,則從AppMaster的內存*一定系數和默認最小overhead中取較大值。

在spark-1.4.1版本中,MEMORY_OVERHEAD_FACTOR的默認值為0.10(之前是0.07),MEMORY_OVERHEAD_MIN默認為384,我們沒有指定spark.yarn.driver.memoryOverhead和spark.yarn.am.memoryOverhead,而amMemory=512M(由spark.yarn.am.memory決定),因此memoryOverhead為max(512*0.10, 384)=384MB。

Executor的memoryOverhead計算方法與此一樣,只是不區分是否集群模式,都默認由spark.yarn.executor.memoryOverhead配置。

  1. 日志和sparkUI上顯示的是executor內部用於緩存計算結果的內存空間,並不是executor所擁有的全部內存。這部分內存是由以下公式計算:
    這里寫圖片描述

Runtime.getRuntime.maxMemory按2048MB算,storage memory大小為1105.92MB,sparkUI顯示的略小於此值,是正常的。

  1. 與上述第2點一樣,storage memory的大小略小於1024*0.9*0.6=552.96MB

  2. 前面提到spark會為container額外申請一部分內存(memoryOverhead),因此,實際為container提交申請的內存大小是2048 + max(2048*0.10, 384) = 2432MB,而yarn在做資源分配時會做資源規整化,即應用程序申請的資源量一定是最小可申請資源量的整數倍(向上取整),最小可申請內存量由yarn.scheduler.minimum-allocation-mb指定,因此,會為container分配3G內存。

———————————————————

驗證

為了驗證上述規則,繼續修改配置參數:

SPARK_EXECUTOR_INSTANCES=4 在yarn集群中啟動的executor進程數

SPARK_EXECUTOR_MEMORY=4G 為每個executor進程分配的內存大小

SPARK_DRIVER_MEMORY=3G 為spark-driver進程分配的內存大小

並在啟動spark-sql時指定spark.yarn.am.memory參數:

bin/spark-sql –master yarn –conf spark.yarn.am.memory=1024m

再看日志信息:

這里寫圖片描述
這里寫圖片描述

yarnUI狀態:
這里寫圖片描述

sparkUI的executors信息:

這里寫圖片描述

可見,AppMaster的實際內存為1024M(1408-384),而其在yarn中的container內存大小為2G(1408大於1G,yarn按資源規整化原則為其分配2G)。

同理,driver的storage memory空間為3G*0.9*0.6=1.62G,executor的storage memory空間為4G*0.9*0.6=2.16G,executor所在container占用5G內存(4096+max(4096*0.10,384)= 4505.6,大於4G, yarn按資源規整化原則為其分配5G)。

Yarn集群的內存總占用空間為2+5*4=22G。

 

 hadoop的job執行在yarn中內存分配調節————Container [pid=108284,containerID=container_e19_1533108188813_12125_01_000002] is running beyond virtual memory limits. Current usage: 653.1 MB of 2 GB physical memory use

 

實際遇到的真實問題,解決方法:

  1.調整虛擬內存率yarn.nodemanager.vmem-pmem-ratio (這個hadoop默認是2.1)

       2.調整map與reduce的在AM中的大小大於yarn里RM可分配的最小值yarn.scheduler.minimum-allocation-mb 大小因為在Container中計算使用的虛擬內存來自

         map虛擬內大小=max(yarn.scheduler.minimum-allocation-mb,mapreduce.map.memory.mb)  *  yarn.nodemanager.vmem-pmem-ratio,同理reduce虛擬內存大小也是這樣計算...

 

具體說明相關參數含義[文章參考:http://blog.chinaunix.net/uid-25691489-id-5587957.html與https://blog.csdn.net/u012042963/article/details/53099638]:

 

ResourceManager配置:

RM的內存資源配置,主要是通過下面的兩個參數進行的(這兩個值是Yarn平台特性,應在yarn-site.xml中配置好):

  yarn.scheduler.minimum-allocation-mb
  yarn.scheduler.maximum-allocation-mb

說明:單個容器可申請的最小與最大內存,應用在運行申請內存時不能超過最大值,小於最小值則分配最小值,從這個角度看,最小值有點想操作系統中的頁;

   最小值還有另外一種用途,計算一個節點的最大container數目。注!!:這兩個值一經設定不能動態改變(此處所說的動態改變是指應用運行時)。

 

NodeManager配置:

NM的內存資源配置,主要是通過下面兩個參數進行的(這兩個值是Yarn平台特性,應在yarn-sit.xml中配置) :
  yarn.nodemanager.resource.memory-mb   ===>每個節點可用的最大內存
  yarn.nodemanager.vmem-pmem-ratio        ===>虛擬內存率
說明:每個節點可用的最大內存:

     RM中的兩個值(yarn.scheduler.minimum-allocation-mb與yarn.scheduler.maximum-allocation-mb)不應該超過此值,

     此數值可以用於計算container最大數目,即:用此值除以RM中的最小容器內存;

   虛擬內存率:

     是占task所用內存的百分比,默認值為2.1倍,

     注意!!:第一個參數是不可修改的,一旦設置,整個運行過程中不可動態修改,且該值的默認大小是8G,即使計算機內存不足8G也會按着8G內存來使用。

 

ApplicationMaster配置:

AM內存配置相關參數,此處以MapReduce為例進行說明(這兩個值是AM特性,應在mapred-site.xml中配置),如下:
  mapreduce.map.memory.mb
  mapreduce.reduce.memory.mb
說明:這兩個參數指定用於MapReduce的兩個任務(Map and Reduce task)的內存大小,其值應該在RM中的最大(yarn.scheduler.maximum-allocation-mb)最小(yarn.scheduler.minimum-allocation-mb)container之間,如果沒有配置則通過如下簡單公式獲得:
    max(MIN_CONTAINER_SIZE, (Total Available RAM) / containers))
一般的reduce應該是map的2倍。

注!!:這兩個值可以在應用啟動時通過參數改變

 

AM中JVM相關設置:

AM中其它與內存相關的參數,還有JVM相關的參數,這些參數可以通過如下選項配置:
  mapreduce.map.java.opts
  mapreduce.reduce.java.opts
說明:這兩個參主要是為需要運行JVM程序(java、scala等)准備的,通過這兩個設置可以向JVM中傳遞參數的,與內存有關的是,-Xmx,-Xms等選項;此數值大小,應該在AM中的mapreduce.map.memory.mb和mapreduce.reduce.memory.mb之間。

 

實際案例:

Container [pid=108284,containerID=container_e19_1533108188813_12125_01_000002] is running beyond virtual memory limits. Current usage: 653.1 MB of 2 GB physical memory used; 5.4 GB of 4.2 GB virtual memory used. Killing container. 

復制代碼
<property> <name>yarn.nodemanager.vmem-pmem-ratio</name> <value>2.1</value> <source>yarn-default.xml</source> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>8192</value> <source>yarn-default.xml</source> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>8192</value> <source>yarn-default.xml</source> </property> <property> <name>yarn.scheduler.minimum-allocation-mb</name> <value>1024</value> <source>yarn-default.xml</source> </property> <property> <name>mapreduce.map.memory.mb</name> <value>1024</value> <source>mapred-default.xml</source> </property> <property> <name>mapreduce.reduce.memory.mb</name> <value>1024</value> <source>mapred-default.xml</source> </property>
復制代碼

 

通過配置我們看到,容器的最小內存和最大內存分別為:1024m和8192m,而reduce設置的默認值為1024m,map也是默認值,所以兩個值都為1024m,所以兩個值和為2G即是log中" 653.1 MB of 2 GB physical memory used" 這個2G。而由於使用了默認虛擬內存率(也就是2.1倍),所以對於Map Task和Reduce Task總的虛擬內存為都為2*2.1=4.2G,這個4.2也是log中的"5.4 GB of 4.2 GB virtual memory used"  計算的這個虛擬內存。而應用的虛擬內存超過了這個數值,故報錯 。解決辦法:在啟動Yarn是調節虛擬內存率或者應用運行時調節內存大小

 

另外一個案例:

Container[pid=41884,containerID=container_1405950053048_0016_01_000284] is running beyond virtual memory limits. Current usage: 314.6 MB of 2.9 GB physical memory used; 8.7 GB of 6.2 GB virtual memory used. Killing container.

復制代碼
        <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>100000</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>10000</value> </property> <property> <name>yarn.scheduler.minimum-allocation-mb</name> <value>3000</value> </property> <property> <name>mapreduce.reduce.memory.mb</name> <value>2000</value> </property> 
復制代碼

 

通過配置我們看到,容器的最小內存和最大內存分別為:3000m和10000m,而reduce設置的默認值小於2000m,map沒有設置,所以兩個值均為3000m,也就是log中的“2.9 GB physical
memory used”。而由於使用了默認虛擬內存率(也就是2.1倍),所以對於Map Task和Reduce Task總的虛擬內存為都為3000*2.1=6.2G。而應用的虛擬內存超過了這個數值,故報錯 。解決辦
法:在啟動Yarn是調節虛擬內存率或者應用運行時調節內存大小。

 

這個調整對應用非常有用!!!

 


免責聲明!

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



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