1. 程式人生 > >Hadoop作業JVM堆優化彙總及JVM複用

Hadoop作業JVM堆優化彙總及JVM複用

問題導讀:
1.mapred.child.java.opts是用來做什麼的?
2.如何讓mapred.child.java.opts的值不能隨便修改?
3.通過什麼引數可以配置作業的Map和Reduce階段的heap的大小?
4.mapreduce.admin.map.child.java.opts和mapreduce.admin.reduce.child.java.opts的作用是什麼?
5.JVM複用的目的是什麼?





前段時間,公司Hadoop叢集整體的負載很高,查了一下原因,發現原來是客戶端那邊在每一個作業上擅自配置了很大的堆空間,從而導致叢集負載很高。下面我就來講講怎麼來現在客戶端那邊的JVM堆大小的設定。


我們知道,在mapred-site.xml配置檔案裡面有個mapred.child.java.opts配置,專門來配置一些諸如堆、垃圾回收之類的。看下下面的配置:

  1. <property>
  2.    <name>mapred.child.java.opts</name>
  3.    <value>-Xmx200m</value>
  4.    <description>Java opts for the task tracker child processes.
  5.    The following symbol, if present, will be interpolated: @
    [email protected]
    is 
  6.    replaced by current TaskID. Any other occurrences of '@' will go unchanged.
  7.    For example, to enable verbose gc logging to a file named for the taskid in
  8.    /tmp and to set the heap maximum to be a gigabyte, pass a 'value' of:
  9.          -Xmx1024m -verbose:gc -Xloggc:/tmp/@[email protected]

  10.    The configuration variable mapred.child.ulimit can be used to control the
  11.    maximum virtual memory of the child processes.
  12.    </description>
  13. </property>
複製程式碼
預設情況下,-Xmx都是配置200m的,但是在實際情況下,這個顯然是不夠用的,所以導致客戶端那邊會設定更大的值。那怎麼來限制使用者隨便設定Xmx的值呢?有下面兩種方法:

一、可以自己定義一個變數,比如如下:

  1. <property>
  2.    <name>mapred.task.java.opts</name>
  3.    <value>-Xmx2000m</value>
  4. </property>
  5. <property>
  6.    <name>mapred.child.java.opts</name>
  7.    <value>${mapred.task.java.opts} -Xmx1000m</value>
  8.    <final>true</final>
  9. </property>
複製程式碼
上面的mapred.task.java.opts屬性是我們自己定義的,可以公佈給使用者配置;然後在mapred.child.java.opts中獲取到mapred.task.java.opts的值,同時mapred.child.java.opts屬性的final被設定為true,也就是不讓客戶修改。所以使用者對mapred.child.java.opts直接配置是無效的;而且這裡我們在獲取${mapred.task.java.opts}之後再添加了-Xmx1000m,而在Java中,如果相同的jvm arg寫在一起,比如”-Xmx2000m -Xmx1000m”,後面的會覆蓋前面的,也就是說最終“-Xmx1000m”才會生效,通過這種方式,我們就可以有限度的控制客戶端那邊的heap size了。同樣的道理,其他想覆蓋的引數我們也可以寫到後面。


我們可以通過
  1. <property> 
  2.   <name>mapred.map.child.java.opts</name> 
  3.   <value> 
  4.      -Xmx512M
  5.   </value> 
  6. </property>
  7. <property> 
  8.   <name>mapred.reduce.child.java.opts</name> 
  9.   <value> 
  10.      -Xmx1024M 
  11.   </value> 
  12. </property>
複製程式碼 來分別配置作業的Map和Reduce階段的heap的大小。


二、通過mapreduce.admin.map.child.java.opts和和mapreduce.admin.reduce.child.java.opts設定
上述限制客戶端那邊隨便設定堆大小是通過重新定義一個變數給使用者使用,這樣使用者得使用新的變數來定義一些JVM相關的設定,如果使用者那邊的指令碼非常多,他們就需要一個一個指令碼的修改mapred.child.java.opts為mapred.task.java.opts。這樣會很不方便。

這裡介紹另外一種方法。可以通過mapreduce.admin.map.child.java.opts和mapreduce.admin.reduce.child.java.opts來限定作業map和reduce的堆的大小。他們都是管理員設定的map/reduce階段申請的container的預設JVM啟動引數。啟動container的命令列會先連線管理員設定引數,然後再連線使用者設定引數。我們來看看Hadoop原始碼是怎麼獲取客戶端和管理員JVM引數的獲取的:

  1. private static String getChildJavaOpts(JobConf jobConf, boolean isMapTask) {
  2.     String userClasspath = "";
  3.     String adminClasspath = "";
  4.     if (isMapTask) {
  5.       userClasspath = 
  6.           jobConf.get(
  7.               JobConf.MAPRED_MAP_TASK_JAVA_OPTS, 
  8.               jobConf.get(
  9.                   JobConf.MAPRED_TASK_JAVA_OPTS, 
  10.                   JobConf.DEFAULT_MAPRED_TASK_JAVA_OPTS)
  11.           );
  12.       adminClasspath = 
  13.           jobConf.get(
  14.               MRJobConfig.MAPRED_MAP_ADMIN_JAVA_OPTS,
  15.               MRJobConfig.DEFAULT_MAPRED_ADMIN_JAVA_OPTS);
  16.     } else {
  17.       userClasspath =
  18.           jobConf.get(
  19.               JobConf.MAPRED_REDUCE_TASK_JAVA_OPTS, 
  20.               jobConf.get(
  21.                   JobConf.MAPRED_TASK_JAVA_OPTS,
  22.                   JobConf.DEFAULT_MAPRED_TASK_JAVA_OPTS)
  23.               );
  24.       adminClasspath =
  25.           jobConf.get(
  26.               MRJobConfig.MAPRED_REDUCE_ADMIN_JAVA_OPTS,
  27.               MRJobConfig.DEFAULT_MAPRED_ADMIN_JAVA_OPTS);
  28.     }
  29.     // Add admin classpath first so it can be overridden by user.
  30.     return adminClasspath + " " + userClasspath;
  31. }
複製程式碼
通過上面的程式碼,我們可以發現Hadoop是先獲取管理員的JVM引數配置,然後連線客戶端那邊JVM引數的配置。這樣如果管理員那邊的配置在客戶端那邊也配置了,那麼客戶端這邊的配置將會覆蓋掉管理員那邊的引數配置。所以我們可以修改原始碼,將 return adminClasspath + ” ” + userClasspath;修改為 return userClasspath + ” ” + adminClasspath;然後在mapred-site.xml檔案做如下配置:
  1. <property>
  2.       <name>mapreduce.admin.map.child.java.opts</name>
  3.       <value>-Xmx1000m</value>
  4. </property>
  5. <property>
  6.       <name>mapreduce.admin.reduce.child.java.opts</name>
  7.       <value>-Xmx1000m</value>
  8. </property>
複製程式碼
這樣,我們就可以覆蓋客戶端那邊的配置。

總結
上面兩種方法雖然能在一定程度上限制客戶端使用堆的大小,但是這樣的解決辦法不是很好的!因為我們設定所有作業的堆大小都是1000M,但是實際情況下,很多作業不一定都用得到1000M;而且在一些情況下,有些作業用到的heap可能大於1000M,這樣會使這樣的作業出現OOM的問題。





這裡找到了另外一篇做一下對比:


前一陣子發現使用者提交的hive query和hadoop job會導致叢集的load非常高,經檢視配置,發現很多使用者擅自將mapred.child.java.opts設定的非常大,比如-Xmx4096m(我們預設設定是-Xmx1024m),  導致了tasktracker上記憶體資源耗盡,進而開始不斷swap磁碟上資料,load飆升。

TaskTracker在spawn一個map/reduce task jvm的時候,會根據使用者JobConf裡面的值設定jvm的引數,然後寫入一個taskjvm.sh檔案中,然後呼叫linux命令"bin/bash -c taskjvm.sh"來執行task,mapred.child.java.opts就是設定jvm的引數之一,在新版本中已經標註Deprecateded,取而代之的是區分Map task和Reduce task的jvm opts,mapred.map.child.java.opts和mapred.reduce.child.java.opts(預設值為-Xmx200m)


當用戶在不設該值情況下,會以最大1G jvm heap size啟動task,有可能導致OutOfMemory,所以最簡單的做法就是設大引數,並且由於這個值不是final,所以使用者在自己的mapred-site.xml中可以覆蓋預設值。但是如果很多使用者都無限度設定的話,high load問題就來了。

其實在構造JVM Args的過程中,是有另外一個admin引數可以覆蓋使用者端設定的mapreduce.admin.map.child.java.opts, mapreduce.admin.reduce.child.java.opts
經測試,如果相同的jvm arg如果寫在後面,比如"-Xmx4000m -Xmx1000m",後面的會覆蓋前面的,“-Xmx1000m”會最終生效,通過這種方式,我們就可以有限度的控制heap size了

最終在mapred-site.xml中加上

  1. <property>  
  2.       <name>mapreduce.admin.map.child.java.opts</name>  
  3.       <value>-Xmx1024m</value>  
  4. </property>  
  5. <property>  
  6.       <name>mapreduce.admin.reduce.child.java.opts</name>  
  7.       <value>-Xmx1536m</value>  
  8. </property>  
複製程式碼

構造child java opts的call stack:  

不過這種方式只是限定了task的jvm heap最大限制,如果使用者hive query優化不夠好還是會丟擲OOM,其實是把問題拋給了使用者, 接下來還要和使用者一起看下到底是哪些query會佔用如此大memory,看看有沒有進一步優化的空間



JVM還可以複用,這樣對於小檔案,可以避免資源浪費

Hadoop預設為每個task(map task 或者 reduce task) 啟動一個jvm。
鑑於目前小檔案過多的問題,設定了jvm複用,即一個job內,多個task共享jvm,避免多次啟動jvm,浪費資源和時間。
測試Job資訊:
map:4715個
reduce:20個
input:  34G
output:  25G
優化前:1464 s
優化後:1375 s
Job執行時間減少 6%
CPU使用率情況:
*注意: mapred.job.reuse.jvm.num.tasks這個引數是客戶端引數,修改不需要重啟tasktracker,可以在提交job的shell或者程式碼中設定。

相關推薦

Hadoop作業JVM優化彙總JVM

問題導讀:1.mapred.child.java.opts是用來做什麼的?2.如何讓mapred.child.java.opts的值不能隨便修改?3.通過什麼引數可以配置作業的Map和Reduce階段的heap的大小?4.mapreduce.admin.map.child.

Java鎖優化思路JVM實現

應用 num nal 高性能 thread collect 傳統 有一個 test 1. 鎖優化的思路和方法 這裏提到的鎖優化,是指在阻塞式的情況下,如何讓性能不要變得太差。但是再怎麽優化,一般來說性能都會比無鎖的情況差一點。 這裏要註意的是,在ReentrantLock中

Hadoop Map&Reduce個數優化設定以及JVM重用

來源:http://irwenqiang.iteye.com/blog/1448164        Hadoop與JVM重用對應的引數是mapred.job.reuse.jvm.num.tasks,預設是1,表示一個JVM上最多可以順序執行的task數目(屬於同一個J

hadoop作業調優引數整理原理(整個mapreduce執行流程都講的清楚,一步一步優化

1 Map side tuning引數 1.1 MapTask執行內部原理 當map task開始運算,併產生中間資料時,其產生的中間結果並非直接就簡單的寫入磁碟。這中間的過程比較複雜,並且利用到了記憶體buffer來進行已經產生的部分結果的快取,並在記憶體bu

JVM優化與相關配置引數

   如果在垃圾回收日誌中觀察到OutOfMemoryError,嘗試把Java堆的大小擴大到實體記憶體的80%~90%。尤其需要注意的是堆空間導致的OutOfMemoryError以及一定要增加空間。比如說,增加-Xms和-Xmx的值來解決old代的OutOfMemoryError,增加-XX:PermSi

java.lang.IllegalStateException: FragmentManager is already executing transactions SmartTabLayout

      在複用 SmartTabLayout  時, 出現了標題所示的錯誤。首先我的場景是Activity下兩個fragment  :A 和 B,A中使用了SmarttabLayout和viewpager結合, B也同樣使用了這個結合, 然後就出現了B

linux網路程式設計之TCP狀態轉換

(1)TCP狀態轉換圖               其中圖中分為三種狀態:實線代表的主動發起連線,虛線代表的被動發起連線,細實線代表的可以雙向發起連線的狀態。 主動發起連線方狀態變化:1)主動發起連線的一方傳送SYN標誌位,進入SYN_SENT狀態,等待接收被髮起連線方

java.lang.IllegalStateException: FragmentManager is already executing transactions SmartTabLayout

  在複用 SmartTabLayout  時, 出現了標題所示的錯誤。首先我的場景是Activity下兩個fragment  :A 和 B,A中使用了SmarttabLayout和viewpager結合, B也同樣使用了這個結合, 然後就出現了B中滑動異常或不顯示了, 網上的答案有幾種情況:   

Android 5.X新特性之RecyclerView基本解析無限

說到RecyclerView,相信大家都不陌生,它是我們經典級ListView的升級版,升級後的RecyclerView展現了極大的靈活性。同時內部直接封裝了ViewHolder,不用我們自己定義ViewHolder就能實現item的回收和複用功能。當然它肯定不

Hadoop作業JVM大小設定優化

Container is running beyond memory limitshttp://stackoverflow.com/questions/21005643/container-is-running-beyond-memory-limits`   [hado

Tomcat性能優化JVM內存工作原理

web linux 了解 stat compact src 返回 共享 disable Java性能優化原則:代碼運算性能、內存回收、應用配置(影響Java程序主要原因是垃圾回收,下面會重點介紹這方面) 代碼層優化:避免過多循環嵌套、調用和復雜邏輯。 Tomcat調優主

Tomcat效能優化JVM記憶體工作原理

Java效能優化原則:程式碼運算效能、記憶體回收、應用配置(影響Java程式主要原因是垃圾回收,下面會重點介紹這方面) 程式碼層優化:避免過多迴圈巢狀、呼叫和複雜邏輯。 Tomcat調優主要內容如下: 1、增加最大連線數 2、調整工作模式 3、啟用gzip壓縮

JVM記憶體引數優化,讓效能飛起來

JVM堆記憶體引數優化,讓效能飛起來 堆記憶體是Java程序的重要組成部分,幾乎所有與應用相關的記憶體空間都和堆有關。現在主要介紹與堆記憶體相關的引數設定,這些引數對Java虛擬機器中非常重要的,也是對程式效能有著重要的影響。讓你徹底脫離OOM記憶體溢位等等帶來

Jvm記憶體的劃分結構和優化,垃圾回收詳解

在JVM中堆空間劃分如下圖所示 上圖中,刻畫了Java程式執行時的堆空間,可以簡述成如下2條 1.JVM中堆空間可以分成三個大區,新生代、老年代、永久代 2.新生代可以劃分為三個區,Eden區,兩個倖存區 在JVM執行時,可以通過配置以下引數改變整個JVM堆的配

Tomcat 調優 JVM 參數優化

error: 收集 permgen object 上傳 服務器軟件 其他 判斷 系統內存 Tomcat 的缺省配置是不能穩定長期運行的,也就是不適合生產環境,它會死機,讓你不斷重新啟動,甚至在午夜時分喚醒你。對於操作系統優化來說,是盡可能的增大可使用的內存容量、提高CPU

Eclipse中檢視調整JVM記憶體大小

一、檢視堆記憶體 設定路徑:Windows > Pregerences > General 勾選右側視窗的show heap status一項 點選 ok,即可在eclipse右下方看到實時的heap情況 二、調整堆記憶體 進入ecli

java JVM 新生代與老年代回收方式

回收方式主要為兩種,複製——清除,與標記——清除(標記 ——整理為標記——清除的升級版)。 新生代為沒有經歷過垃圾回收或者經歷次數沒有到達轉入老年代的物件。 老年帶為經歷過多次回收仍然存在的物件。或者由虛擬機器規則轉入老年代的新生代。 新生代在建立兌現的時候記憶體無法滿足會

Tomcat 調優 JVM 引數優化

Tomcat 的預設配置是不能穩定長期執行的,也就是不適合生產環境,它會宕機,讓你不斷重新啟動,甚至在午夜時分喚醒你。對於作業系統優化來說,是儘可能的增大可使用的記憶體容量、提高CPU 的頻率,保證檔案系統的讀寫速率等。經過壓力測試驗證,在併發連線很多的情況下,CPU 的

Tomcat調優JVM引數優化

        為了提升效能,首先就要對程式碼進行動靜分離,讓 Tomcat 只負責 jsp 檔案的解析工作。如採用 Apache 和 Tomcat 的整合方式,他們之間的連線方案有三種選擇,JK、http_proxy 和 ajp_proxy。相對於 JK 的連線方式,後兩種在配置上比較簡單的,靈活性方面也一

Jvm記憶體的劃分結構和優化,垃圾回收詳解(詳細解答篇)

1.S0與S1的區間明顯較小,有效新生代空間為Eden+S0/S1,因此有效空間就大,增加了記憶體使用率 2.有利於物件代的計算,當一個物件在S0/S1中達到設定的XX:MaxTenuringThreshold值後,會將其分到老年代中,設想一下,如果沒有S0/S1,直接分成兩個區,該如何計算物件經過了多少次G