性能文章>记一次MapReduce的内存溢出>

记一次MapReduce的内存溢出原创

1年前
5731010

背景:

最近使用MapReduce做离线数据清洗,在map段做简单的数据过滤,有经纬度的发送到reduce端,没经纬的过滤掉。reduce端将数据整理出来,按业务模型拼接成字符串写入HDFS。供hive作为外表进行后续数据处理分析。

问题:

该批数据总共2T大小,MapReduce执行第一次时,不出意料的崩溃了。每次都大概在map阶段执行到61%左右。

排查:

查看日志发现果然内存溢出:java.lang.OutOfMemoryError: GC overhead limit exceeded

Exception in thread thread_name: java.lang.OutOfMemoryError: GC Overhead limit exceededCause: The detail message “GC overhead limit exceeded” indicates that the garbage collector is running all the time and Java program is making very slow progress. After a garbage collection, if the Java process is spending more than approximately 98% of its time doing garbage collection and if it is recovering less than 2% of the heap and has been doing so far the last 5 (compile time constant) consecutive garbage collections, then a java.lang.OutOfMemoryError is thrown. This exception is typically thrown because the amount of live data barely fits into the Java heap having little free space for new allocations.Action: Increase the heap size. The java.lang.OutOfMemoryError exception for GC Overhead limit exceeded can be turned off with the command line flag -XX:-UseGCOverheadLimit.

大概意思就是说,JVM花费了98%的时间进行垃圾回收,而只得到2%可用的内存,频繁的进行内存回收(最起码已经进行了5次连续的垃圾回收),JVM就会曝出java.lang.OutOfMemoryError: GC overhead limit exceeded错误。本质上还是堆内存不足。

其实对于大数据执行来说内存溢出问题司空见惯。按照惯例一套标准流程,减小每个map的split字节大小,增加map数,增加每个container的堆内存,增加每个map的堆内存,能想到的参数我试了个遍。其实缕了一下代码,我认为我们的map不应该存在内存溢出的情况。因为并没有进行复杂的关联计算,并且不会存在数据倾斜问题。但是任务每次还是在60%左右卡死,同时,我观察到一个现象。每次程序崩溃的时候,yarn 的任务追踪页面都会反应的异常慢,看来我之前想的方向有问题,看来不是map容器的堆内存溢出。

image.png

异常图如上,仔细缕了一遍异常,发现是ContainerLauncherImpl 这个类的报错,意思是容器启动的时候发生的问题。

image.png

查了下hadoop 这块的代码,果然是申请容器的时候出了问题,MRAppMaster负责向yarn的resourcemanager去申请资源启动容器。初步得出了应该是MRAppMaster的内存溢出。
ApplicationMaster向资源调度器申请执行任务的资源容器Container,运行用户自己的程序任务job(我们可以用浏览器看yarn
里的job进展),监控整个任务的执行,跟踪整个任务的状态,处理任务失败以异常情况。这也对应了我们看yarn上的任务监控会崩溃的情况。

解决:

通过调整参数,yarn.app.mapreduce.am.command-optsyarn.app.mapreduce.am.resource.mb加大了MRAppMaster的内存。同时分析待处理的源数据。发现每个文件10MB大小,总共有18万,MapReduce处理文件,默认使用FileInputFormat,但是这个处理小文件是,会每一个小文件生成一个map,所以以为着原来我们的任务有18万个map,这应该突破了原来的MRAppMaster所能维护的map的极限,频繁的申请创建、销毁container也消耗了大量的计算资源,导致了内存溢出、任务崩溃。hadoop处理大量小文件建议使用CombineFileInputFormat来合并输入数据,减少map数量。修改完之后,map数量锐减到2800多个,程序不再报内存溢出,同时提升了执行速度。

至此,问题得到了解决。

请先登录,再评论

暂无回复,快来写下第一个回复吧~

为你推荐

不起眼,但是足以让你有收获的JVM内存分析案例
分析 这个问题说白了,就是说有些int[]对象不知道是哪里来的,于是我拿他的例子跑了跑,好像还真有这么回事。点该 dump 文件详情,查看相关的 int[] 数组,点该对象的“被引用对象”,发现所
从一起GC血案谈到反射原理
前言 首先回答一下提问者的问题。这主要是由于存在大量反射而产生的临时类加载器和 ASM 临时生成的类,这些类会被保留在 Metaspace,一旦 Metaspace 即将满的时候,就会触发 Fu
关于内存溢出,咱再聊点有意思的?
概述 上篇文章讲了JVM在GC上的一个设计缺陷,揪出一个导致GC慢慢变长的JVM设计缺陷,可能有不少人还是没怎么看明白的,今天准备讲的大家应该都很容易看明白 本文其实很犹豫写不写,因为感觉没有
协助美团kafka团队定位到的一个JVM Crash问题
概述 有挺长一段时间没写技术文章了,正好这两天美团kafka团队有位小伙伴加了我微信,然后咨询了一个JVM crash的问题,大家对crash的问题都比较无奈,因为没有现场,信息量不多,碰到这类问题我
又发现一个导致JVM物理内存消耗大的Bug(已提交Patch)
概述 最近我们公司在帮一个客户查一个JVM的问题(JDK1.8.0_191-b12),发现一个系统老是被OS Kill掉,是内存泄露导致的。在查的过程中,阴差阳错地发现了JVM另外的一个Bug。这个B
JVM实战:优化我的IDEA GC
IDEA是个好东西,可以说是地球上最好的Java开发工具,但是偶尔也会卡顿,仔细想想IDEA也是Java开发的,会不会和GC有关,于是就有了接下来对IDEA的GC进行调优 IDEA默认JVM参数: -
不起眼,但是足以让你收获的JVM内存案例
今天的这个案例我觉得应该会让你涨姿势吧,不管你对JVM有多熟悉,看到这篇文章,应该还是会有点小惊讶的,不过我觉得这个案例我分享出来,是想表达不管多么奇怪的现象请一定要追究下去,会让你慢慢变得强大起来,
谨防JDK8重复类定义造成的内存泄漏
概述 如今JDK8成了主流,大家都紧锣密鼓地进行着升级,享受着JDK8带来的各种便利,然而有时候升级并没有那么顺利?比如说今天要说的这个问题。我们都知道JDK8在内存模型上最大的改变是,放弃了Perm