前段时间,公司Hadoop集群整体的负载很高,查了一下原因,发现原来是客户端那边在每一个作业上擅自配置了很大的堆空间,从而导致集群负载很高。下面我就来讲讲怎么来现在客户端那边的JVM堆大小的设置。
我们知道,在mapred-site.xml配置文件里面有个mapred.child.java.opts配置,专门来配置一些诸如堆、垃圾回收之类的。看下下面的配置:

 <property>
<name>mapred.child.java.opts</name>
<value>-Xmx200m</value>
<description>Java opts for the task tracker child processes.
The following symbol, if present, will be interpolated: @taskid@ is
replaced by current TaskID. Any other occurrences of '@' will go unchanged.
For example, to enable verbose gc logging to a file named for the taskid in
/tmp and to set the heap maximum to be a gigabyte, pass a 'value' of:-Xmx1024m -verbose:gc -Xloggc:/tmp/@taskid@.gc
The configuration variable mapred.child.ulimit can be used to control the
maximum virtual memory of the child processes.
</description>
</property>

默认情况下,-Xmx都是配置200m的,但是在实际情况下,这个显然是不够用的,所以导致客户端那边会设置更大的值。那怎么来限制用户随便设置Xmx的值呢?有下面两种方法:

  

一、可以自己定义一个变量,比如如下:

<property>
<name>mapred.task.java.opts</name>
<value>-Xmx2000m</value>
</property> <property>
<name>mapred.child.java.opts</name>
<value>${mapred.task.java.opts} -Xmx1000m</value>
<final>true</final>
</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了。同样的道理,其他想覆盖的参数我们也可以写到后面。

我们可以通过

<property>
<name>mapred.map.child.java.opts</name>
<value>
-Xmx512M
</value>
</property> <property>
<name>mapred.reduce.child.java.opts</name>
<value>
-Xmx1024M
</value>
</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参数的获取的:

private static String getChildJavaOpts(JobConf jobConf, boolean isMapTask) {
String userClasspath = "";
String adminClasspath = "";
if (isMapTask) {
userClasspath =
jobConf.get(
JobConf.MAPRED_MAP_TASK_JAVA_OPTS,
jobConf.get(
JobConf.MAPRED_TASK_JAVA_OPTS,
JobConf.DEFAULT_MAPRED_TASK_JAVA_OPTS)
);
adminClasspath =
jobConf.get(
MRJobConfig.MAPRED_MAP_ADMIN_JAVA_OPTS,
MRJobConfig.DEFAULT_MAPRED_ADMIN_JAVA_OPTS);
} else {
userClasspath =
jobConf.get(
JobConf.MAPRED_REDUCE_TASK_JAVA_OPTS,
jobConf.get(
JobConf.MAPRED_TASK_JAVA_OPTS,
JobConf.DEFAULT_MAPRED_TASK_JAVA_OPTS)
);
adminClasspath =
jobConf.get(
MRJobConfig.MAPRED_REDUCE_ADMIN_JAVA_OPTS,
MRJobConfig.DEFAULT_MAPRED_ADMIN_JAVA_OPTS);
} // Add admin classpath first so it can be overridden by user.
return adminClasspath + " " + userClasspath;
}

  通过上面的代码,我们可以发现Hadoop是先获取管理员的JVM参数配置,然后连接客户端那边JVM参数的配置。这样如果管理员那边的配置在客户端那边也配置了,那么客户端这边的配置将会覆盖掉管理员那边的参数配置。所以我们可以修改源码,将 return adminClasspath + ” ” + userClasspath;修改为 return userClasspath + ” ” + adminClasspath;然后在mapred-site.xml文件做如下配置:

<property>
<name>mapreduce.admin.map.child.java.opts</name>
<value>-Xmx1000m</value>
</property>
<property>
<name>mapreduce.admin.reduce.child.java.opts</name>
<value>-Xmx1000m</value>
</property>

这样,我们就可以覆盖客户端那边的配置。
  

总结

  上面两种方法虽然能在一定程度上限制客户端使用堆的大小,但是这样的解决办法不是很好的!因为我们设定所有作业的堆大小都是1000M,但是实际情况下,很多作业不一定都用得到1000M;而且在一些情况下,有些作业用到的heap可能大于1000M,这样会使这样的作业出现OOM的问题。

Hadoop作业JVM堆大小设置优化 [转]的更多相关文章

  1. jvm详情——6、堆大小设置简单说明

    年轻代的设置很关键JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:64 ...

  2. JVM堆内存设置和测试

    1. Java虚拟机内存结构 划分新生代和老年代,这样只在新生代分配内存,从而简化了新对象的分配.另外新生代和老年代使用不同的GC算法,可以更有效的清除不再需要的对象.从上图可以看出,JVM内存由yo ...

  3. 【转】JVM 堆内存设置原理

    堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...

  4. [转]JVM 堆内存设置原理

    堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...

  5. JVM 堆内存设置原理

    堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...

  6. JVM 堆内存设置原理(转)

    堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...

  7. JVM堆内存设置

    今天碰到了一个题目,讲的是关于堆内存的问题,题目如下   下面哪种情况会导致持久区jvm堆内存溢出? A.循环上万次的字符串处理 B.在一段代码内申请上百M甚至上G的内存 C.使用CGLib技术直接操 ...

  8. JVM堆内存参数优化,让性能飞起来

    堆内存是Java进程的重要组成部分,几乎所有与应用相关的内存空间都和堆有关.现在主要介绍与堆内存相关的参数设置,这些参数对Java虚拟机中非常重要的,也是对程序性能有着重要的影响.让你彻底脱离OOM内 ...

  9. java 调整jvm堆大小上限

    针对单个类,eclipse中调整jvm的运行参数,加上这么一句: -Xmx80m 即可把堆上限调整到80m. 关键字: BEA JRockit

随机推荐

  1. DBCP、C3P0、Proxool 、 BoneCP开源连接池的比《转》

     简介   使用评价  项目主页  DBCP DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序用使用 可以设置最大和最小连接,连接等待时 ...

  2. [转载] linux 程序运行过程中替换文件

    今天被朋友问及“Linux下可以替换运行中的程序么?”,以前依稀记得Linux下是可以的(而Windows就不让),于是随口答道“OK”.结果朋友发来一个执行结果:(test正在运行中)# cp te ...

  3. SG 复习全部 (全部SG 总览)

    1. SQL 基础 进入查缺补漏阶段 2. PL/SQL 进入 practice 阶段 3. Fundamental 1 这部分还是比较重要 architecture 数据库启动与关闭步骤 insta ...

  4. 使用ioctl“实现”自定义的系统调用

    http://www.educity.cn/Linux/1242138.html 最近做的项目跟Linux内核的关系比较大,我们的项目需要在用户态触发一些内核态的代码运行.众所周知,内核态的代码是不能 ...

  5. Target runtime Apache Tomcat v7.0 is not defined.

    打开项目,找到.settings--->org.eclipse.wst.common.project.facet.core 修改这个文件中: <?xml version="1.0 ...

  6. (六)动手写第一个shell

    1.编辑器.编译器.运行方法(脚本的3种执行方法)(1)shell程序是文本格式的,只要是文本编辑器都可以.但是因为我们的shell是要在linux系统下运行的,所以换行符必须是'\n',而windo ...

  7. Android的启动模式(上)

    1. 基本介绍 大家平时只要懂一点Android知识的话,都一定会知道,一个应用的组成,往往包含了许多的activity组件,每个activity都应该围绕用户的特定动作进行跳转设计.比如说,一个电话 ...

  8. Eclipse启动tomcat时报错:Multiple Contexts have a path of "/xxx"

    今天使用Eclipse启动tomcat部署项目时,遇到一个奇怪的错误: Could not publish server configuration for Tomcat v6.0 Server at ...

  9. MYSQL 编码方式 ------导入 .sql 文件 报编码错误

    在做计量泵上位机时,利用MYSQL存储数据,建表hisruninfo(计量泵历史运行数据表). 表格式为utf8,查过数据库 格式 同样为utf8 导入该hisruninfo.sql文件时,并没有报错 ...

  10. UnicodeEncodeError

    UnicodeEncodeError at /admin/shop/product/add/ 'ascii' codec can't encode characters in position 0-1 ...