码迷,mamicode.com
首页 > 其他好文 > 详细

记一则罕见的hive字段值异常引起map阶段的OOM

时间:2014-05-20 22:15:47      阅读:422      评论:0      收藏:0      [点我收藏+]

标签:mapreduce   hadoop   hadoop运维   

   前段时间遇到了一个很诡异的发生的Map阶段的OOM异常,花了些时间才找到原因,这个简要记录一下。

   先看log。

节点一的TaskTracker的log:

bubuko.com,布布扣

节点二的TaskTracker的log:

bubuko.com,布布扣

节点三的TaskTracker的log:

bubuko.com,布布扣

其他节点的TaskTracker中的log都和slave4的一样的:

bubuko.com,布布扣


故障分析:

   OOM是一个比较常见的故障,其中发生在reduce阶段最为常见,最有可能是数据通过map函数后,shuffle到reduce端处理时由于分布问题导致某个分组的值太多出现OOM。另外,OOM也可能出现在DataNode进程上,这个属于比较罕见的情况,这个情况我就遇到过,是因为系统进程数配置的限制导致OOM的,具体情况可以看我这篇blog:http://zengzhaozheng.blog.51cto.com/8219051/1370125。对于上面的这个出现在Map阶段的OOM比较奇怪,一般在Map阶段不会出现OOM,因为一个Map task只处理一个split的数据的,而我们集群的block size只是配到64MB,照道理一个split size的大小应该为64MB左右(具体split size大小计算请看:http://zengzhaozheng.blog.51cto.com/8219051/1347777),从这点看来Map阶段不会出现OOM情况。从另外一方面看,Map阶段出现OOM的唯一地方就是通过io.sort.mb参数所控制的环形缓冲区当中,其对用的是Sort和spill环节,集群中环形缓冲区配到了500MB,整个虚拟机内存mapred.map.child.java.opts也配到了2G,照道理不会出现OOM。另外,为了安全起见还是通过改变这个2个参数去测测,结果还是意料之中出现OOM。

   再回过头来看看日志,不同节点的TaskTracker的日志都有所不同,其中的节点一、二、三的共同点就是heap OOM和Buffer的读写错误,其他节点则都是报了一些文件错误。那么整个OOM错误的日志被归为2类,其中其他节点则都是报了一些文件错误很可能是由于节点一、二、三出现OOM引起的,具体原因还是要根据堆栈信息追一下源码,找到TaskLog类的createForWrite方法:

/**
 * Open the specified File for write access, ensuring that it does not exist.
 * @param f the file that we want to create
 * @param permissions we want to have on the file (if security is enabled)
 *
 * @throws AlreadyExistsException if the file already exists
 * @throws IOException if any other error occurred
 */
public static FileOutputStream createForWrite(File f, int permissions)
throws IOException {
  if (skipSecurity) {
    return insecureCreateForWrite(f, permissions);
  } else {
    // Use the native wrapper around open(2)
    try {
      FileDescriptor fd = NativeIO.open(f.getAbsolutePath(),
        NativeIO.O_WRONLY | NativeIO.O_CREAT | NativeIO.O_EXCL,
        permissions);
      return new FileOutputStream(fd);
    } catch (NativeIOException nioe) {
      if (nioe.getErrno() == Errno.EEXIST) {
        throw new AlreadyExistsException(nioe);
      }
      throw nioe;
    }
  }
}

   从这段源码我们可以看出TaskTracker在创建TaskLog的时候出现了错误,其原因是TaskLog句柄已经存在了。呵呵,这个不难理解,当Map Task出现OOM之后,根据MapReduce的容错机制,其所在的TaskTracker进程会尝试重新启动的Map Task并且为其创建相同的TaskLog的文件句柄,但是由于出现OOM程序异常终止了并且之前的TaskLog文件句柄已经创建过但是没有被正常关闭,所以在重启启动Map Task是会检测到已经存在该句柄,所以报这个错。到这里第二类错误日志信息原因已经被解决,接下来集中精力看这个OOM错误原因。

   这种情况的Map阶段出现的OOM之前没有遇到过,一时没有什么头绪,回过头来看看写的HiveSql脚本,功能很简单就是统计一个省当天网关日志的上网uv,对号码字段(mdn)做了一个count distinct最后group by了一下,当天日志做完ETL后才300多G左右,300G多的数据不算大。再看了看节点一、二报的这2个OOM信息,发现有IO读写错误的信息,主要是BufferedReader读取和用StreamDecoder解码出错,这下子想到会不会是mdn字段值有问题,出现乱码什么的导致读写错误最终引起OOM呢?试验一把!!首先检查mdn长度,distinct length(mdn)看看,照道理应该只有一个值并且这个值为11才对因为号码是固定的13位数,令人惊奇的是出现了3个不同的值,分别为11、16和18!在HiveSql中加上where length(mdn)=11,将长度为16和18的排除掉,重新执行HiveSql相当正常一点错误都没有!!查看号码mdn长度为16和18的究竟长什么模样,分别执行select * from tb_cdr where day=‘20140403‘ and length(mdn)=16 limit 5 和 select * from tb_cdr where day=‘20140403‘ and length(mdn)=18 limit 5,发现记录中有些乱码,这下子搞明白了。Map Task运行的时候数据流中包含了非法字符例如:EOF、NOP等东西,导致BufferedReader读取和StreamDecoder解码出错,正如节点一、二日志中看到的,进一步导致OOM。


总结:

对于这个OOM故障,按照一般的MapReduce框架运行原理思维和平常的OOM故障处理方式是很难揪出问题所在的。解决这样问题的关键点在于日志中的细小信息点,如BufferedReader读取和StreamDecoder的出错点,你不能够一看到OOM就不往日志下面看了,这种细小信息可以引导你到一个正确的方向,不至于漫无目的的瞎搞。另外,搞hadoop方面的技术人员最好是要精通于写MapReduce程序,我觉得这个很重,会写MapReduce程序那么你对MapReduce的整体处理流程一定会很清楚,出现问题能够比较容易找出原因。如果只会HiveSql,那么出现简单的错误自己都无法下手搞的,甚至连简单的数据倾斜原理都不知道,这样你写的HiveSql性能也许很低效的,所以一切都需要回到本质问题上来,hive的本质就是将HiveSql翻译成MapReduce程序。





本文出自 “一只风骚的蚂蚁” 博客,谢绝转载!

记一则罕见的hive字段值异常引起map阶段的OOM,布布扣,bubuko.com

记一则罕见的hive字段值异常引起map阶段的OOM

标签:mapreduce   hadoop   hadoop运维   

原文地址:http://zengzhaozheng.blog.51cto.com/8219051/1413583

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!