背景:我司作为某运营商公司的技术咨询公司,发现有第三方开发公司在使用HBase 1.1.2 (HDP 2.4.2.258版本)一段时间使用正常后,从某一天开始报OOM,从而导致RegionServer宕机。

故障排查步骤

  1. 查看 regionserver的log和stdout。由于是突然宕机,log没有任何error信息,stdout 因为自动拉起以及默认启动脚本是重定向覆盖,所以被洗掉了;而oom dump当时还没开启,无任何明显提示信息。
  2. regionserver的log中尽管没有发现error信息,但发现了许多warning,BucketCache: Failed allocation for ${block_id}org.apache.hadoop.hbase.io.hfile.bucket.BucketAllocatorException: Allocation too big size=21342038。这虽然不是错误,但其实是个很有用的提示信息,说明可能存在着有许多大的block,无法写入bucketcache读缓存中。
  3. 尝试重新拉起regionserver,但由于业务方疏忽,他们表示已停了所有程序,但却依然没完全停止读取hbase程序,因此反复拉起regionserver失败,此时可看到日志  java.lang.OutOfMemoryError: Requested array size exceeds VM limit
  4. 根据stacktrace进去读源码,发现是在做rpc fetch data的时候,ByteBufferOutputStream对象时用一个数组cache数据,bytes超过capacity上限后会把当前的capacity乘以2,new一个新的byte数组,把旧的数组内容copy到新的去。这种底层的类似c的写法可以减少对象和随机读内存的开销。但是源码很蠢,分配的上限是Integer.MAX_VALUE,而众所周知,Oracle/OpenJDK 7的数组只允许开到 Integer.MAX_VALUE - 2 ,因为用户一个查询过大,即使内存和网络足够好也会OOM导致RegionServer宕机,这明显是个bug。[HBase 14978] [HBase 14946] 从issue看应该是在1.2.0以后加了对multi的限制,尝试从服务前端避免这种问题发生,但本人尚未仔细阅读1.2.0的源码去确认是否真的修复。
  5. 由于业务方不知是对自己的数据不熟悉还是其他原因,一直不承认有大数据,于是我们通过反复实验定位找回了查询挂的语句,开了oom dump 获取了宕机前的内存快照。通过对ByteBuffer对象的分析和反二进制化,发现了挂机时其内存吃到了1g,按照capacity翻倍,再翻倍就是2g超出了数组上限,完全符合错误栈信息。
  6. 从快照里获取了一个看起来比较大的rowkey,get出来整个row有38m。而后我们又写了个scan程序对全表scan并统计size,发现整体几百k以上的数据也不少,还有少部分是10m以上的。在他们的20000/batch 的multi-get的场景,基本很容易挂。拿出数据与业务方对峙后,业务方承认数据可能是存在脏数据,他们之前实际遇到过类似问题。在写入时报了 keyvalue size too large 的问题,但他们毫不在意,把配置的size改成了512m就写入算了。

至此,故障已被成功排查。对于咨询团队来说,主要的任务已经完成了。

附:OOM错误完整 stacktrace
FATAL [IndexRpcServer.handler=5,queue=0,port=60020J regionserver.HRegionServer: Run out of memory; HRegionServer will abort itself immediately
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:57)
at java.nio.ByteBuffer.allocate(ByteBuffer.java:331)
at org.apache.hadoop.hbase.io.ByteBufferOutputStream.checkSizeAnd6row(ByteBufferOutputStream.java:74)
at org.apache.hadoop.hbase.io.ByteBufferOutputStream.write(ByteBufferOutputStream.java:112) at org.apache.hadoop.hbase.KeyValue.oswrite{KeyVdlue.java:2881)
at org.apache.hadoop.hbase.codec.KeyValueCodec^KeyVdlueEncoder.writetKeyVdlueCodec.java:60)
at org.apache.hadoop.hbase.ipc.IPCUtil.buildCeilBlock(IPCUti1.java:120) at org.apache.hadoop.hbase.ipc.RpcServer$Call.setResponse(RpcServer.java:384)
at org.apache.hadoop.hbase.ipc.CallRunner.run(CallRunner.java:128)
at org.apache.hadoop.hbase.ipc.RpcExecutor.consumerLoop(RpcExecutor.java:112)
at org.apache.hadoop.hbase.ipc.RpcExecutor$l.run(RpcExecutor.java:92)
at java.lang.Th read.run(Th read.java:745)

相关原理简要分析

bucketcache

参考:HBase BlockCache系列 – 走进BlockCache HBase BlockCache系列 - 探求BlockCache实现机制

BlockCache是Region Server级别的,一个Region Server只有一个Block Cache,在Region Server启动的时候完成Block Cache的初始化工作。读数据时,会先访问blockcache,blockcache没数据则从hdfs读取数据尝试写入读缓存,写失败则会抛warning直接返回数据,否则从读缓存中返回数据。bucketcache是hbase读缓存blockcache的一种实现,听说是由阿里贡献的,其他的还有LRUBlockCache,SlabCache等。大致的发展可以梳理为 LRUBlockCache -> DoubleBlockCache(LRU + Slab) -> CombinedBlockCache(LRU+Bucket)。

bucketcache 可以配置四种模式:none禁用,heap堆内,off-heap堆外,file文件。一般推荐开启,file主要是针对ssd场景,off-heap配置不好会出现另外的direct memory OOM问题,具体计算较复杂,参见Configuring Off-heap Memory (BucketCache) - HortonWorks

bucketcache实际上和本次故障的直接关系不大,因为通过源码可以发现IPCUtil获取的outputstream只有堆上的ByteBufferOutputStream,只是其warning信息可以帮我们进一步佐证有异常过大数据的猜想。BucketCache的相关调用和实现逻辑可参见HFileReaderV2BucketCache两个类。

Best Practice

避免此类问题,须注意如下HBase使用技巧:

  1. 负责入库的需做好数据限制,谨慎修改 keyvalue max size 限制,脏数据或不重要的数据可适当裁剪或丢弃,实在较大的数据考虑存hdfs,hbase存路径去指向文件。
  2. 读取时需大致估算平均每行数据大小,并适当留出冗余的内存,来决定一个multi get的batch大小。不需要的列字段就尽量不要读,避免oom也可以节省性能。
  3. column family和qualifier尽可能短而精确,因为每一个keyvalue都会存qualifier。
  4. 如无必要,表的字段尽量不太太多。
  5. 动态qualifier慎用,除非你对你自己的数据有足够清楚的上限了解。
  6. (其他)索引表和数据表尽量分离,不然scan会带来额外不必要的开销。

HBase 查询导致RegionServer OOM故障复盘的更多相关文章

  1. 公司内部一次关于OOM故障复盘分享

    最近笔者有点忙,这次OOM事故发生过去两周前,记得笔者那天正带着家人在外地玩,正中午跟友人吃饭的时候,钉钉连续告警爆表,接着就是钉钉电话(显示广东抬头)一看就知道BBQ了,又一次故障发生了,今天把那次 ...

  2. 执行SQL查询导致磁盘耗尽故障演示

            a fellow in IMG wechat group 2 met an error about running out of disk space when using MySQL ...

  3. 《MySQL》一次MySQL慢查询导致的故障

    本文转载自 http://www.jb51.net/article/70955.htm 我们知道分析MySQL语句查询性能的方法除了使用EXPLAIN 输出执行计划,还可以让MySQL记录下查询超过指 ...

  4. 一次bug死磕经历之Hbase堆内存小导致regionserver频繁挂掉

    环境如下: Centos6.5 Apache Hadoop2.7.1 Apache Hbase0.98.12 Apache Zookeeper3.4.6 JDK1.7 Ant1.9.5 Maven3. ...

  5. HBASE 优化之REGIONSERVER

    HBASE 优化之REGIONSERVER 一,概述 本人在使用优化regionserver的过程有些心得,借此随笔的机会,向大家介绍我的心得,有些是网上拿来的有些是自己在使用过程自己的经验,希望对大 ...

  6. 一次线上OOM故障排查经过

    转贴:http://my.oschina.net/flashsword/blog/205266 本文是一次线上OOM故障排查的经过,内容比较基础但是真实,主要是记录一下,没有OOM排查经验的同学也可以 ...

  7. hbase查询基于标准sql规范中间件Phoenix

    Phoenix是个很好的hbase 查询工具,在hbase中安装也很简单,可以按照 http://www.cnblogs.com/laov/p/4137136.html 这个连接中进行配置客户端和服务 ...

  8. 关于运维之故障复盘篇-Case Study

    关于故障的事后复盘,英文名 Case Study是非常有必要做的,当然是根据故障的级别,不可能做到每个故障都Case Study,除非人员和时间充足: 文档能力也是能力的一种,一般工程师的文档能力比较 ...

  9. Android中解决图像解码导致的OOM问题

    Android中解决图像解码导致的OOM问题 原文链接:http://blog.csdn.net/zjl5211314/article/details/7042017

随机推荐

  1. [转]利用ssh传输文件

    利用ssh传输文件 http://www.cnblogs.com/jiangyao/archive/2011/01/26/1945570.html 在linux下一般用scp这个命令来通过ssh传输文 ...

  2. C语言之冒泡排序、选择排序、折半查询、进制查表

    菜单导航 1.冒泡排序 2.选择排序 3.折半查询 4.进制查表(十进制转二进制.八进制.十六进制) 一.冒泡排序 //1.冒泡排序 /** 一组无序数字,进行从小到大排序 冒泡排序的过程:就是每个循 ...

  3. 如何禁止某个linux用户访问某些文件夹及执行某些命令

    方案1: 给这个文件A增加个a的隐藏属性,只能增加数据不能删除修改数据,只有root能设置这个隐藏属性 chattr +a A lsattr A 可以查看隐藏属性 方案2: 修改文件所属用户和组,普通 ...

  4. js前端ajax提交list集合参数至后端

    var orderNosList = new Array(); var rows = $("#dg_linkOrder").datagrid("getChecked&qu ...

  5. php图文合成文字居中(png图片合成)

    header('Content-type:text/html;charset=utf-8'); /** * png图文合成 by wangzhaobo * @param string $pic_pat ...

  6. 51Nod1675 序列变换 数论 莫比乌斯反演

    原文http://www.cnblogs.com/zhouzhendong/p/8665675.html 题目传送门 - 51Nod1675 题意 给定序列$a,b$,让你求满足$\gcd(x,y)= ...

  7. 学习Spring必须了解的基础知识——回调机制

    上面这张图如果能看得懂就能理解什么是回调机制: A对象在调用a()方法时会调用B对象的b()方法,b()方法必须能调用A对象的callback()方法. 谁白了:a()方法有B对象b()方法的引用,b ...

  8. 查出了a表,然后对a表进行自查询,a表的别名t1,t2如同两张表,因为t1,t2查询的条件不一样,真的如同两张表,关联两张表,可以将两行或者多行数据合并成一行,不必使用wm_concat()函数。为了将t2表的数据全部查出来使用了右连接。

    with a as( select nsr.zgswj_dm, count(distinct nsr.djxh) cnt, 1 z from hx_fp.fp_ly fp, hx_dj.dj_nsrx ...

  9. SQL语句中单引号、双引号和反引号的区分

    反引号 反引号:反引号一般在Esc键的下方,为了区分MySQL的保留字与普通字符而引入的符号. 一般我们建表时都会将表名,库名都加上反引号来保证语句的执行度. 例如: SELECT * FROM `u ...

  10. HDU 3829 Cat VS Dog (最大独立集)【二分图匹配】

    <题目链接> 题目大意: 动物园有n条狗.m头猫.p个小孩,每一个小孩有一个喜欢的动物和讨厌的动物.如今动物园要转移一些动物.假设一个小孩喜欢的动物在,不喜欢的动物不在,他就会happy. ...