Hadoop作业JVM堆大小设置优化
https://www.iteblog.com/archives/981
Container is running beyond memory limitshttp://stackoverflow.com/questions/21005643/container-is-running-beyond-memory-limits`
[hadoop] - Container [xxxx] is running beyond physical/virtual memory limits. http://www.cnblogs.com/liuming1992/p/5040262.html
当运行mapreduce的时候,有时候会出现异常信息,提示物理内存或者虚拟内存超出限制,默认情况下:虚拟内存是物理内存的2.1倍。异常信息类似如下:
Container [pid=13026,containerID=container_1449820132317_0013_01_000012] is running beyond physical memory limits. Current usage: 1.0 GB of 1 GB physical memory used; 1.7 GB of 2.1 GB virtual memory used. Killing container. Dump of the process-tree for container_1449820132317_0013_01_000012 : |- PID PPID PGRPID SESSID CMD_NAME USER_MODE_TIME(MILLIS) SYSTEM_TIME(MILLIS) VMEM_USAGE(BYTES) RSSMEM_USAGE(PAGES) FULL_CMD_LINE |- 13044 13026 13026 13026 (java) 4479 494 1696595968 271631 /home/hadoop/cdh5.2.4/jdk1.7.0_79/bin/java -Djava.net.preferIPv4Stack=true -xxx
我们可以看到该异常信息是提示物理内存超过限制,但是通过我们查看代码我们发现我们最终使用的内存没有达到1G,只有500M-。(具体原因没有细查)最终我们发现影响这个代码执行的参数分别是:
参数 | 默认值 | 描述 |
yarn.scheduler.minimum-allocation-mb | 1024 | 每个container请求的最低jvm配置,单位m。如果请求的内存小于该值,那么会重新设置为该值。 |
yarn.scheduler.maximum-allocation-mb | 8192 | 每个container请求的最高jvm配置,单位m。如果大于该值,会被重新设置。 |
yarn.nodemanager.resource.memory-mb | 8192 | 每个nodemanager节点准备最高内存配置,单位m |
yarn.nodemanager.vmem-pmem-ratio | 2.1 | 虚拟内存和物理内存之间的比率,如果提示virtual memory limits的时候,可以将该值调大。 |
yarn.nodemanager.pmem-check-enabled | true | 是否进行物理内存限制比较,设置为false,不会进行大小的比较 |
yarn.nodemanager.vmem-check-enabled | false | 是否进行虚拟内存限制比较。 |
mapreduce.map.memory.mb | 1024 | map内存申请大小,单位m |
mapreduce.reduce.memory.mb | 1024 | reduce内存申请大小,单位m |
mapred.child.java.opts | -Xmx200 | map/reduce执行参数设置,可以参数Hadoop Mapreduce Error: GC overhead limit exceeded |
针对该异常信息,有多种方式进行解决:
第一种:
直接将yarn.nodemanager.pmem-check-enabled和yarn.nodemanager.vmem-check-enabled设置为false,那么可以杜绝异常信息的产生。
第二种:
如果异常信息提示的是virtual memory不够,那么可以将yarn.nodemanager.vmem-pmem-ratio参数改大,那么也可以避免异常信息的产生。
第三种:
修改mapreduce参数,设置修改如下:
mapreduce.map.memory.mb = (1~2倍) * yarn.scheduler.minimum-allocation-mb
mapreduce.reduce.memory.mb = (1~4倍) * yarn.scheduler.minimum-allocation-mb
1. mapred.child.java.opts = -XmxTm(T数字要小于map和reduce的设置value)
2. mapreduce.map.java.opts=-Xmx(<mapreduce.map.memory.mb)m
mapreduce.reduce.java.opts=-Xmx(<mapreduce.reduce.memory.mb)m
总结:最终运行参数给定的jvm堆大小必须小于参数指定的map和reduce的memory大小,最好为70%以下。
hadoop源码涉及到地方:
1. org.apache.hadoop.mapred.MapReduceChildJVM.getChildJavaOpts
2. org.apache.hadoop.yarn.server.nodemanager.containermanager.monitor.ContainersMonitorImpl.MonitoringThread.run()<398-465行>(进行内存限制判断)
3. org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerImpl.LaunchTransition.transition()<647-658行>(进行物理内存和虚拟内存大小限制计算和赋值)
物理内存大小其实就是mapreduce.map.memory.mb和mapreduce.reduce.memory.mb的一个大小值
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
mapred.child.java.opts:当需要处理超大数据(mapper大于10?)最好将值设置成-Xmx1024m或者更高(-Xmx2048m)才能避免出现“核心已转储”这种jvm内存溢出的错误!!
http://slaytanic.blog.51cto.com/2057708/1101360/
name | value | Description |
hadoop.job.history.location | job历史文件保存路径,无可配置参数,也不用写在配置文件里,默认在logs的history文件夹下。 | |
hadoop.job.history.user.location | 用户历史文件存放位置 | |
io.sort.factor | 30 | 这里处理流合并时的文件排序数,我理解为排序时打开的文件数 |
io.sort.mb | 600 | 排序所使用的内存数量,单位兆,默认1,我记得是不能超过mapred.child.java.opt设置,否则会OOM |
mapred.job.tracker | hadoopmaster:9001 | 连接jobtrack服务器的配置项,默认不写是local,map数1,reduce数1 |
mapred.job.tracker.http.address | 0.0.0.0:50030 | jobtracker的tracker页面服务监听地址 |
mapred.job.tracker.handler.count | 15 | jobtracker服务的线程数 |
mapred.task.tracker.report.address | 127.0.0.1:0 | tasktracker监听的服务器,无需配置,且官方不建议自行修改 |
mapred.local.dir | /data1/hdfs/mapred/local, /data2/hdfs/mapred/local, ... |
mapred做本地计算所使用的文件夹,可以配置多块硬盘,逗号分隔 |
mapred.system.dir | /data1/hdfs/mapred/system, /data2/hdfs/mapred/system, ... |
mapred存放控制文件所使用的文件夹,可配置多块硬盘,逗号分隔。 |
mapred.temp.dir | /data1/hdfs/mapred/temp, /data2/hdfs/mapred/temp, ... |
mapred共享的临时文件夹路径,解释同上。 |
mapred.local.dir.minspacestart | 1073741824 | 本地运算文件夹剩余空间低于该值则不在本地做计算。字节配置,默认0 |
mapred.local.dir.minspacekill | 1073741824 | 本地计算文件夹剩余空间低于该值则不再申请新的任务,字节数,默认0 |
mapred.tasktracker.expiry.interval | 60000 | TT在这个时间内没有发送心跳,则认为TT已经挂了。单位毫秒 |
mapred.map.tasks | 2 | 默认每个job所使用的map数,意思是假设设置dfs块大小为64M,需要排序一个60M的文件,也会开启2个map线程,当jobtracker设置为本地是不起作用。 |
mapred.reduce.tasks | 1 | 解释同上 |
mapred.jobtracker.restart.recover | true | false | 重启时开启任务恢复,默认false |
mapred.jobtracker.taskScheduler | org.apache.hadoop.mapred. CapacityTaskScheduler org.apache.hadoop.mapred. JobQueueTaskScheduler org.apache.hadoop.mapred. FairScheduler |
重要的东西,开启任务管理器,不设置的话,hadoop默认是FIFO调度器,其他可以使用公平和计算能力调度器 |
mapred.reduce.parallel.copies | 10 | reduce在shuffle阶段使用的并行复制数,默认5 |
mapred.child.java.opts |
-Xmx2048m -Djava.library.path= |
每个TT子进程所使用的虚拟机内存大小 |
tasktracker.http.threads | 50 | TT用来跟踪task任务的http server的线程数 |
mapred.task.tracker.http.address | 0.0.0.0:50060 | TT默认监听的httpIP和端口,默认可以不写。端口写0则随机使用。 |
mapred.output.compress | true | false | 任务结果采用压缩输出,默认false,建议false |
mapred.output.compression.codec | org.apache.hadoop.io. compress.DefaultCodec |
输出结果所使用的编解码器,也可以用gz或者bzip2或者lzo或者snappy等 |
mapred.compress.map.output | true | false | map输出结果在进行网络交换前是否以压缩格式输出,默认false,建议true,可以减小带宽占用,代价是会慢一些。 |
mapred.map.output.compression.codec | com.hadoop.compression. lzo.LzoCodec |
map阶段压缩输出所使用的编解码器 |
map.sort.class | org.apache.hadoop.util. QuickSort |
map输出排序所使用的算法,默认快排。 |
mapred.hosts | conf/mhost.allow | 允许连接JT的TT服务器列表,空值全部允许 |
mapred.hosts.exclude | conf/mhost.deny | 禁止连接JT的TT列表,节点摘除是很有作用。 |
mapred.queue.names | ETL,rush,default | 配合调度器使用的队列名列表,逗号分隔 |
mapred.tasktracker.map. tasks.maximum |
12 | 每服务器允许启动的最大map槽位数。 |
mapred.tasktracker.reduce. tasks.maximum |
6 | 每服务器允许启动的最大reduce槽位数 |
http://blog.csdn.net/lalaguozhe/article/details/9076895
前一阵子发现用户提交的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中加上
<property> <name>mapreduce.admin.map.child.java.opts</name> <value>-Xmx1024m</value> </property> <property> <name>mapreduce.admin.reduce.child.java.opts</name> <value>-Xmx1536m</value> </property>