Hadoop之内存问题

一 发生很多Job OOM现象

那几天运维发现很多OOM,一直不断在Full GC。我们知道Full GC一旦发生超过几分钟,其他的线程均停止工作,只有垃圾回收线程工作。

第一个猜想是运行的Job,也就是我们运行任务内存资源不够用。所以猜想是container所启动的YarnChild的JVM内存大小不够,或者配置小了,导致内存不够用。我们就把内存配大了些。

mapreduce.map.memory.mb: 为每一个MapTask申请的资源,也就是每一个MapTask最多只能使用这么内存,默认1024M

mapreduce.reduce.memory.mb为每一个ReduceTask申请的资源,一个ReduceTask最多只能使用这么内存,默认1024M

注意:设置了这个,就起作用了吗?答案是不一定的。原因在于,这里只是限制MapTask 和 ReduceTask最多使用的内存限制。

但是container所启动的YarnChild的JVM是不是就是这个配置呢,答案是不是的。启动的JVM的内存参数取决于:

mapreduce.map.java.opts:这个是Container启动MapTask的YarnChild进程设置的堆大小参数,默认1024M

mapreduce.reduce.java.opts: 这个是Container启动ReduceTask的YarnChild进程设置的堆大小参数, 默认1024M

 

比如:

mapreduce.reduce.memory.mb=5120  //设置reduce container的内存大小

mapreduce.reduce.java.opts=-Xms2000m -Xmx4600m; //设置reduce任务的JVM参数

 

如果只是把任务所允许的资源调高了,但是启动任务JVM参数并没有调高,那么还是不起作用,就相当于你可以使用1G来运行某个程序,但是JVM只能使用512M,就算你可以使用2G来运行这个程序,那么JVM还是只能使用512M.

总结:

优先设置container启动的YarnChild进程的堆参数,如果还不够,则在考虑增大mapreduce.map.memory.mbmapreduce.reduce.

memory.mb参数,然后在来调整堆参数。

 

所以理想的配置应该是java.opts的值必须大于等于memory.mb的值.所以说,这种配置不当的方式也会引发频繁的Full GC.

 

mapreduce.map.memory.mb最好是mapreduce.reduce.memory.mb2

 

mapreduce.map.java.optsmapreduce.reduce.java.opts应该不会大于mapreduce.map.memory.mbmapreduce.reduce.memory.mb

 

# mapreduce.map.java.optsmapreduce.map.java.opts.max.heap最好是mapreduce.reduce.java.optsmapreduce.reduce.java.opts.max.heap参数的0.85

mapreduce.map.java.opts, mapreduce.map.java.opts.max.heap=1.6G
mapreduce.reduce.java.opts,mapreduce.reduce.java.opts.max.heap=3.3G

hadoop自身已经对此进行了contaienr级别的监控,对于所有启动过container,他会额外开启一个叫container-monitor的线程,专门有对于这些container的pmem(物理内存),vmem(虚拟内存)的监控.相关的配置属于如下:

yarn.nodemanager.pmem-check-enabled:是否检查物理内存

yarn.nodemanager.vmem-check-enabled:是否检查虚拟内存

这两个参数默认是开启的。

一旦这个container所使用的内存超过JVM配置的这个内存,就会把这个container杀掉

 

 

 

二 Reduce在copy阶段内存占用过大

这是reduce从map取数据阶段报的错,reduce从map取数阶段使用的buffer可以占到reduce任务最大堆的70%的内存。报错之前copy还在运行,而reduce阶段其他过程占用了超过30%的内存,这个时候copy阶段继续取数,扩展buffer的时候,申请不到内存就报错了。

 

针对这个我们可以限制copy阶段占用buffer的大小:

mapreduce.reduce.shuffle.input.buffer.percent:默认是70%,我们可以把这个参数设置成0.5 或者更小一点。

 

另外我们需要注意另外一个参数,就是可以控制shuffle并行度的参数:mapreduce.reduce.shuffle.parallelcopies

 

因为mapreduce.reduce.shuffle.input.buffer.percent* mapreduce.reduce.

shuffle.parallelcopies< 1,否则就会报错:

Error: org.apache.hadoop.mapreduce.task.reduce.Shuffle$ShuffleError:error in shuffle in fetcher#1

 

二 YARN 内存资源优化配置

2.1yarn.nodemanager.resource.memory-mb

这个参数其实是设置NodeManager 预备从本机申请多少内存量的,用于所有Container 的分配及计算。这个参数相当于一个阈值,限制了NodeManager 能够使用的服务器的最大内存量,以防止NodeManager 过度消耗系统内存,导致最终服务器宕机。这个值可以根据实际服务器的配置及使用,适度调整大小。

yarn.nodemanager.resource.memory-mb=32GB
yarn.nodemanager.resource.cpu-vcores=32core

 

2.2yarn.nodemanager.vmem-pmem-ratio,默认是2.1

NodeManager接收到 ApplicationMaster 传递过来的Container 后,会用Container 的物理内存大小 (pmem)* yarn.nodemanager.vmem-pmem-ratio 得到 Container 的虚拟内存大小的限制,即为vmemLimit:

 

然后,NodeManager在monitor 线程中监控Container 的 pmem(物理内存)和 vmem(虚拟内存)的使用情况。如果当前 vmem 大于vmemLimit 的限制

 

Monitor每隔 3 秒钟就更新一次每个Container 的使用情况;更新的方式是:

 

查看/proc/pid/stat 目录下的所有文件,从中获得每个进程的所有信息;

根据当前Container 的 pid 找出其所有的子进程,并返回这个Container 为根节点,子进程为叶节点的进程树;在 Linux 系统下,这个进程树保存在ProcfsBasedProcessTree 类对象中;

然后从ProcfsBasedProcessTree 类对象中获得当前进程 (Container) 总虚拟内存量和物理内存量。

 

由此大家应该立马知道了,内存量是通过/proc/pid/stat 文件获得的,且获得的是该进程及其所有子进程的内存量。所以,这里的 vmem 就是 OS 层面的虚拟内存概念。

 

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

yarn.scheduler.minimum-allocation-mb:单个container可以申请到的最小内存量

yarn.scheduler.maximum-allocation-mb:单个container可以申请到的最大内存量

#我们可以根据这个yarn.scheduler.minimum-allocation-mb参数计算一个节点最大container数量:yarn.nodemanager.resource.memory-mb

/单个 container可以申请到最小内存量

 

# yarn.scheduler.maximum-allocation-mb不能大于yarn.nodemanager.

resource.memory-mb即每一个container可以申请最大内存量不能超过分配给NodeManager的内存量

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(大数据/Hadoop)