Yarn下Mapreduce的記憶體引數理解&xml引數配置
Container是什麼?
Container就是一個yarn的java程序,在Mapreduce中的AM,MapTask,ReduceTask都作為Container在Yarn的框架上執行,你可以在RM的網頁上【8088埠】看到Container的狀態
基礎
Yarn的ResourceManger(簡稱RM)通過邏輯上的佇列分配記憶體,CPU等資源給application,預設情況下RM允許最大AM申請Container資源為8192MB(“yarn.scheduler.maximum-allocation-mb“),預設情況下的最小分配資源為1024M(“yarn.scheduler.minimum-allocation-mb“),AM只能以增量(”yarn.scheduler.minimum-allocation-mb“)和不會超過(“yarn.scheduler.maximum-allocation-mb“)的值去向RM申請資源,AM負責將(“mapreduce.map.memory.mb“)和(“mapreduce.reduce.memory.mb“)的值規整到能被(“yarn.scheduler.minimum-allocation-mb“)整除,RM會拒絕申請記憶體超過8192MB和不能被1024MB整除的資源請求【記憶體增量】。
本文基於Hadoop2.6;下面提到的配置項最好都要設定以覆蓋預設值,以便調優。
1、yarn-site.xml 設定
yarn進行資源管理的時候:以contain作為最小單位來進行資源分配的。
事實上Hadoop所有設定都可以寫在同一個xml中,但是為了自己檢視方便,模組化,所以分開寫。
yarn-site.xml主要設定yarn的基本配置,以yarn開頭的配置項。修改後必須重啟叢集生效。
mapred-site.xml主要設定mapreduxe任務的配置項;這個檔案修改後不需重啟叢集。
1.1 NM設定(NodeManager)
NM的記憶體資源配置,主要是通過下面兩個引數進行的(這兩個值是Yarn平臺特性,應在yarn-sit.xml中配置) :
yarn.nodemanager.resource.memory-mb 預設8GB
yarn.nodemanager.vmem-pmem-ratio 預設2.1
說明:第一個引數:該結點向作業系統申請的記憶體總量,RM中的兩個值不能超過此值。此數值可以用於計算container最大數目,即:用此值除以RM中的最小容器記憶體。第二個:虛擬記憶體率,是佔task所用記憶體的百分比,預設值為2.1倍。如報錯虛擬記憶體溢位,則提高該值。
注意:第一個引數預設大小是8G,即使計算機記憶體不足8G也會按著8G記憶體來使用,所有計算機記憶體小於8GB應該調低這個值。
1.2 RM設定(ResourceManager)
RM的記憶體資源配置,主要是通過下面的兩個引數進行的(這兩個值是Yarn平臺特性,應在yarn-sit.xml中配置):
yarn.scheduler.minimum-allocation-mb 預設1GB
yarn.scheduler.maximum-allocation-mb 預設8GB
說明:單個容器可申請的最小與最大記憶體,應用在執行申請記憶體時不能超過最大值,應用申請小於最小值則會分配最小值,從這個角度看,最小值有點像作業系統中的頁。最小值還有另外一種用途,用來計算一個節點的最大container數目。注:這兩個值一經設定不能動態改變(此處所說的動態改變是指需要重啟叢集生效)。
2、mapred-site.xml 設定見文後附錄
2.1 AM設定(ApplicationManager)
AM記憶體配置相關引數,此處以MapReduce為例進行說明(這兩個值是AM特性,應在mapred-site.xml中配置),如下:
mapreduce.map.memory.mb 預設
mapreduce.reduce.memory.mb 預設
說明:單個Map/Reduce task 申請的記憶體大小,其值應該在RM中的最大和最小container值之間。如果沒有配置則通過如下簡單公式獲得:
max(MIN_CONTAINER_SIZE, (Total Available RAM) / containers))
一般reduce記憶體大小應該是map的2倍。注:這兩個值可以在應用啟動時通過引數改變,可以動態調整;
2.2 AM JVM設定
AM中其它與記憶體相關的引數,還有JVM相關的引數,這些引數可以通過,如下選項配置:
mapreduce.map.java.opts 預設
mapreduce.reduce.java.opts 預設
說明:這兩個參主要是為需要執行JVM程式(java、scala等)準備的,通過這兩個設定可以向JVM中傳遞引數的,與記憶體有關的是,-Xmx,-Xms等選項。此數值大小,應該在AM中的map.mb和reduce.mb之間。
2.3總結
AM為Map/Reduce task向RM申請資源,RM按照mini和max、資源增量的值為task分配一個固定大小的container供task使用。RM可以分配下去的資源總量受到NM配置的值限制。
3、注意:
在hadoop2及以上版本中,map和reduce task 是執行在container中的。mapreduce.{map|reduce}.memory.mb 被yarn用來設定container的記憶體大小。如果container的記憶體超限,會被yarn殺死。在container中,為了執行map和reduce task,yarn會在contaner中啟動一個jvm來執行task任務。mapreduce.{map|reduce}.java.opts用來設定container啟動的jvm相關引數,通過設定Xmx來設定map 或者reduce task的最大堆記憶體。
理論上,{map|reduce}.java.opts設定的最大堆記憶體要比{map|reduce}.memory.mb小。一般設定為一般設定為0.75倍的memory.mb即可;因為在yarn container這種模式下,JVM程序跑在container中,需要為java code等非JVM的記憶體使用預留些空間。
執行中的設定方法例如:xml中也可設定
hadoop jar -Dmapreduce.reduce.memory.mb=4096 -Dmapreduce.map.java.opts=-Xmx3276
4、常見記憶體溢位報錯&解決
預設情況下,yarn.nodemanager.vmem-pmem-ratio被設定為2.1,這意味著,每個map或者task任務只能使用2.1倍(”mapreduce.reduce.memory.mb”) or (“mapreduce.map.memory.mb”) 大小的虛擬記憶體,如果使用的量超出則會被nm殺掉。
例如:日誌中常見報錯:
1、Container xxx is running beyond physical memory limits
2、java heap space
3、Error: GC overhead limit exceeded
報錯1:Current usage: 1.1gb of 2.0gb physical memory used; 4.6gb of 4.2gb virtual memory used. Killing container.【即虛擬記憶體溢位】;
**方法一:提高yarn.nodemanager.vmem-pmem-ratio = 5或者更高;【推薦】**
方法二:yarn.nodemanager.vmem-check-enabled =false ;關閉虛擬記憶體檢查;不推薦
方法三:提高實體記憶體分配,相應的虛擬記憶體自然就多了,但是這樣不是最優
報錯2:Current usage: 2.1gb of 2.0gb physical memory used; 3.6gb of 4.2gb virtual memory used. Killing container.【即實體記憶體溢位】;
方法一:mapreduce.map.memory.mb = 3GB以上,然後測試這個map/reduce task需要使用多少記憶體才夠用,提高這個值直到不報錯為止。
方法二:提高yarn.scheduler.minimum-allocation-mb = 3GB以上,同理【不推薦】
5、記憶體分配增量/規整因子/incrementMemory
為了易於管理資源和排程資源,Hadoop YARN內建了資源規整化演算法,它規定了最小可申請資源量、最大可申請資源量和資源規整化因子,規整化因子是用來規整化應用程式資源的,應用程式申請的資源如果不是該因子的整數倍,則將被修改為最小的整數倍對應的值,公式為ceil(a/b)*b,其中a是應用程式申請的資源,b為規整化因子。對於規整化因子,不同調度器不同,具體如下:
FIFO和Capacity Scheduler,規整化因子等於最小可申請資源量,不可單獨配置。
Fair Scheduler:規整化因子通過引數yarn.scheduler.increment-allocation-mb和yarn.scheduler.increment-allocation-vcores設定,預設是1024和1。
通過以上介紹可知,應用程式申請到資源量可能大於資源申請的資源量,比如YARN的最小可申請資源記憶體量為1024,規整因子是1024,如果一個應用程式申請1500記憶體,則會得到2048記憶體,如果規整因子是512,則得到1536記憶體。
如下圖:map container的記憶體(“mapreduce.map.memory.mb”)被設定為1536mb 。但是AM會為其申請了2048m的記憶體,因為am的最小分配單位/增量(yarn.scheduler.minimum-allocation-mb)被設定為1024,也就是以1GB為單位往上加。這是一種邏輯上的分配,這個值被NodeManager用來監控該程序記憶體資源的使用率,如果mapTask的堆記憶體使用率超過了2048MB,NM將會把這個task給殺掉。
從上面的圖可以看出map,reduce,AM container的JVM,“JVM”矩形代表服務程序,“Max heap”,“Max virtual”矩形代表NodeManager對JVM程序的最大記憶體和虛擬記憶體的限制。
When a mapreduce job completes you will see several counters dumped at the end of the job.The three memory counters below show how much physical memory was allocated vs virtual memory.
對於56G記憶體的NM來說,如果全部跑map則56/3大約跑18個container
大概瞭解完以上的引數之後,mapreduce.map.java.opts和mapreduce.map.memory.mb引數之間,有什麼聯絡呢?
通過上面的分析,我們知道如果一個yarn的container超除了heap設定的大小,這個task將會失敗,我們可以根據哪種型別的container失敗去相應增大mapreduce.{map|reduce}.memory.mb去解決問題。 但同時帶來的問題是叢集並行跑的container的數量少了,所以適當的調整記憶體引數對叢集的利用率的提升尤為重要。
對cpu的設定引數:
在yarn的框架中,CPU的配置決定了一個任務的生死,CPU只是決定了任務的完成效率。所以CPU的設定只是簡單列出來。
yarn.scheduler.minimum-allocation-vcores:最小可申請CPU數,預設是1
yarn.scheduler.maximum-allocation-vcores:最大可申請CPU數,預設是4
yarn.nodemanager.resource.cpu-vcores:叢集向系統申請的總可用CPU數目,預設是8
mapreduce.map.cpu.vcores:task container申請的CPU數目,預設是1
完結!
附錄1-我的yarn-site.xml配置:
<?xml version="1.0"?>
<configuration>
<!-- Site specific YARN configuration properties
下面的配置項中值的大小,特別是記憶體大小,通過每個節點logs中的yarn-hadoop-nodemanager-Slave1.log 檔案中檢視日誌來判斷;出錯行形如:
running beyond virtual memory limits. Current usage: 484.0 MB of 2 GB physical memory used; 4.9 GB of 4.2 GB virtual memory used. Killing container.
在yarn-hadoop-resourcemanager-Slave1.log日誌檔案中:形如:表示記憶體和cpu資源分配:
例如:總的結點資源:<memory:16000, vCores:8>==<memory:10240, vCores:5>+<memory:5760, vCores:3>
Released container container_1511512572160_0003_01_000025 of capacity <memory:2048, vCores:1> on host Slave1:42899, which currently has 5 containers, <memory:10240, vCores:5> used and <memory:5760, vCores:3> available,
-->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>Slave1</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.nodemanager.pmem-check-enabled</name>
<value>true</value>
<description>檢測實體記憶體的使用是否超出分配值,若任務超出分配值,則將其殺掉,預設true。</description>
</property>
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>true</value>
<description>檢測虛擬記憶體的使用是否超出;若任務超出分配值,則將其殺掉,預設true。在確定記憶體不會洩漏的情況下可以設定此項為 False;</description>
</property>
<property>
<name>yarn.nodemanager.vmem-pmem-ratio</name>
<value>8</value>
<description>任務每使用1MB實體記憶體,最多可使用虛擬記憶體量比率,預設2.1;在上一項中設定為false不檢測虛擬記憶體時,此項就無意義了</description>
</property>
<property>
<name>yarn.nodemanager.resource.cpu-vcores</name>
<value>12</value>
<description>該節點上YARN可使用的總核心數;一般設為cat /proc/cpuinfo| grep "processor"| wc -l 的值。預設是8個;</description>
</property>
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>16000</value>
<description>該節點上YARN可使用的實體記憶體總量,【向作業系統申請的總量】預設是8192(MB)</description>
</property>
<property>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>3072</value>
<description>單個容器/排程器可申請的最少實體記憶體量,預設是1024(MB);一般每個contain都分配這個值;即:capacity memory:3072, vCores:1,如果提示實體記憶體溢位,提高這個值即可;</description>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>8000</value>
<description>單個容器申請最大值</description>
</property>
<property>
<description>The minimum allocation for every container request at the RM,
in terms of virtual CPU cores. Requests lower than this will throw a
InvalidResourceRequestException.</description>
<name>yarn.scheduler.minimum-allocation-vcores</name>
<value>1</value>
</property>
<property>
<description>The http address of the RM web application.</description>
<name>yarn.resourcemanager.webapp.address</name>
<value>${yarn.resourcemanager.hostname}:8088</value>
</property>
</configuration>
附錄2-我的mapred-site.xml:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file.
-->
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>Slave1:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>Slave1:19888</value>
</property>
<property>
<name>mapreduce.map.cpu.vcores</name>
<value>2</value>
<description>每個MapTask容器申請的核心數;預設1</description>
</property>
<property>
<name>mapreduce.map.memory.mb</name>
<value>4096</value>
<description>每個Map task容器申請的記憶體大小;預設1G</description>
</property>
<property>
<name>mapreduce.map.java.opts</name>
<value>-Xmx3072m</value>
<description>map使用的JVM的堆大小heapsize;根據單個mapper/reducer容器記憶體進行調整,heapsize不能大於單個mapper/reducer容器記憶體值,一般設定為mapreduce.map.memory.mb的85%左右</description>
</property>
<!--reduce階段的設定 -->
<property>
<name>mapreduce.reduce.cpu.vcores</name>
<value>2</value>
<description>每個ReduceTask容器申請的核心數;預設1</description>
</property>
<property>
<name>mapreduce.reduce.memory.mb</name>
<value>8192</value>
<description>Reduce task申請的記憶體大小</description>
</property>
<property>
<name>mapreduce.reduce.java.opts</name>
<value>-Xmx6144m</value>
<description>Reduce階段的JVM的堆大小;同上</description>
</property>
</configuration>