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

记一次MapReduce的内存溢出原创

2年前
6175011

背景:

最近使用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多个,程序不再报内存溢出,同时提升了执行速度。

至此,问题得到了解决。

点赞收藏
technology
请先登录,感受更多精彩内容
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

【全网首发】一次想不到的 Bootstrap 类加载器带来的 Native 内存泄露分析

【全网首发】一次想不到的 Bootstrap 类加载器带来的 Native 内存泄露分析

记一次“雪花算法”造成的生产事故的排查记录

记一次“雪花算法”造成的生产事故的排查记录

【全网首发】一次疑似 JVM Native 内存泄露的问题分析

【全网首发】一次疑似 JVM Native 内存泄露的问题分析

解读JVM级别本地缓存Caffeine青出于蓝的要诀2 —— 弄清楚Caffeine的同步、异步回源方式

解读JVM级别本地缓存Caffeine青出于蓝的要诀2 —— 弄清楚Caffeine的同步、异步回源方式

单服务并发出票实践

单服务并发出票实践

刺激,线程池的一个BUG直接把CPU干到100%了。

刺激,线程池的一个BUG直接把CPU干到100%了。

11
0