场景:

        生产查询系统用hbase+es构建,一套老的hdp集群,一套新的cdh集群。cdh集群数据由hdp迁移过来,目前已全部完成,完成后两套集群双写,写入方式都是通过spark put方式(也可以用bulkload)。但是会出现一种现象,就是cdh集群写的速度比hdp要慢1/2左右,数据量小不太明显,数据量大的时候特别明显。

问题描述:

        当写入数据量特别大或者字段特多的时候,hdp能正常写入,cdh会很快失败,并报一个错:Hbase RegionTooBusyException:over memstore limit =512.0m

        也就是在hbase集群中向几个大表put数据时,会出现RegionTooBusyException的异常,该异常报错为超过了memstore的上限。

问题分析:

        查阅资料,发现这个over memstore limit =512.0m 是这么来的:hbase.hregion.memstore.flush.size(默认128M)*hbase.hregion.memstore.block.multiplier(默认4)=512M

解决方式:

        既然这样,那调整这两个参数是不是就可以了,于是,根据不同hbase表写入量大小,调整hbase.hregion.memstore.flush.size值为256M,512M,最大的调了2G。

查询超时:

        开始大部分hbase表都能写成功了,但是到后面慢慢的又不行了,甚至在写大表的时候会造成很多查询超时,这种情况是无法接受的。当时已经造成了一定生产影响,只能把cdh大数据写入的停掉。

思考:

        实际上还是没有理解hbase写入原理,随意的修改生产参数,险些造成验证的生产事故。

重新分析:

        cdh的hbase版本比hdp的要高,正常不可能出现hdp成功,cdh失败的情况才对。肯定是hdp调整了某些参数,cdh没有调。对比发现果然有一个重要的参数cdh没有调,就是hbase.hstore.blockingStoreFileshdp默认是10,运维调成了500,而cdh这个参数是16。这个参数有什么作用,也写参考了下面的文章才知道。

原理参考:

文末参考链接,内容借鉴过来记录一下:

异常代码片段:

hdp版hbase0.98:

  private void checkResources()
    throws RegionTooBusyException {
    // If catalog region, do not impose resource constraints or block updates.
    if (this.getRegionInfo().isMetaRegion()) return;

    if (this.memstoreSize.get() > this.blockingMemStoreSize) {
      blockedRequestsCount.increment();
      requestFlush();
      throw new RegionTooBusyException("Above memstore limit, " +
          "regionName=" + (this.getRegionInfo() == null ? "unknown" :
          this.getRegionInfo().getRegionNameAsString()) +
          ", server=" + (this.getRegionServerServices() == null ? "unknown" :
          this.getRegionServerServices().getServerName()) +
          ", memstoreSize=" + memstoreSize.get() +
          ", blockingMemStoreSize=" + blockingMemStoreSize);
    }
  }

cdh版hbase2.1:

  void checkResources() throws RegionTooBusyException {
    // If catalog region, do not impose resource constraints or block updates.
    if (this.getRegionInfo().isMetaRegion()) return;

    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();
    if (mss.getHeapSize() + mss.getOffHeapSize() > this.blockingMemStoreSize) {
      blockedRequestsCount.increment();
      requestFlush();
      // Don't print current limit because it will vary too much. The message is used as a key
      // over in RetriesExhaustedWithDetailsException processing.
      throw new RegionTooBusyException("Over memstore limit=" +
        org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize) +
        ", regionName=" +
          (this.getRegionInfo() == null? "unknown": this.getRegionInfo().getEncodedName()) +
          ", server=" + (this.getRegionServerServices() == null? "unknown":
              this.getRegionServerServices().getServerName()));
    }
  }

Region在每次进行put时,会进行resource的检查。
默认情况下:512M = memstore(128M) * multiplier(4)

原因分析:

一般来说memstore超过hbase.hregion.memstore.flush.size(默认128M),会flush形成HFile。

当写入数据过快时,导致产生大量HFile,当HFile数量超过配置hbase.hstore.blockingStoreFiles(默认10),hbase会进行compaction(合并),compaction会阻塞memstore flush操作,阻塞最长时长hbase.hstore.blockingWaitTime(默认值90000,即90s),当超过该时间后,如果compaction还未完成,memstore flush也会停止阻塞。

但是正是在flush阻塞这段时间内,memstore的大小超过了上限:

hbase.hregion.memstore.flush.size*hbase.hregion.memstore.block.multiplier(默认为4)=512M,此时,region将拒绝所有写请求,所以客户端抛出RegionTooBusyException,并在一定时间后重试。

解决方案:

1.在hbase内存允许的前提下,提高hbase.hregion.memstore.block.multiplier或者hbase.hregion.memstore.flush.size参数,在flush阻塞的这段时间,允许更多的数据写到memstore。

        风险:增加了regionserver oom概率,修改该参数,需要进行大数据量写入测试。

我就是改了这个参数,险些造成严重的生产事故。

2.减少阻塞时间hbase.hstore.blockingwaittime(比如到30s),加快memstore flush到hdfs上的速度,从而减少memstore数据大小触碰到上限的时间,也就能减少拒绝写请求的时间。

        风险:1、增加了compaction的压力,

                   2、占用磁盘IO,可能会影响到其他服务。

3.一般出现RegionTooBusyException,表示大量写入数据量比较大,这种场景更好的选择可能是采用bulkload导入方式。

事实证明,大数据量的改bulkload方式也不行,还是会报错,我试过。

4.调大hbase.hstore.blockingStoreFiles(默认10) ,比如改成500,调大这个参数,减缓compaction(合并),进而减小阻塞队列。网上还有说是GC原因的,怎么调都不好使。

这个生产hdp环境已经试验过可行,而且肯定是之前运维已经趟过水了,可惜调优的材料也没见着。。

优化点

  1. hbase.hregion.flush.size  默认128M   调大   有风险
  2. hbase.regionserver.global.memstore.lowerLimit  默认0.95   regionserver级别  慎改
  3. hbase.hregion.memstore.block.multiplier  默认4
  4. hbase.regionserver.global.memstore.upperLimit  默认0.4
  5. hbase.hstore.blockingStoreFiles  默认10,调成500或者更大
  6. hbase.hregion.max.filesize  默认35G   调成1000G
  7. 全量表删除重建,regions调大,最好节点数整数倍
  8. 手动合并hfile
  9. hbase.hstore.blockingWaitTime  默认90秒
  10. 全量大表调整跑批频率,每天跑改成每周两三次,除非业务硬性要求每天跑,hbase会自动合并小文件,跑的太频繁来不及合并

附:生产调优配置

模块参数名oldnew
serverhbase master maximum memory2GB4GB
servernumber of handlers per gegionserver30300
serverhbase regionserver maximum memory20GB50GB
clientmaximum record size1MB10MB
diskmaximum region file size10GB1000GB
diskhbase.hregion.majorcompaction7days0hours0days0hors
diskmaximum files for compaction1012
timeoutszookeeper session timeout90s120s
timeoutshbase rpc timeout90s240s
regionserverregionservers maximum value for -Xmn512MB4096MB
generalmaximum store files before minor compaction36
advanced hbase-envhbase_user_nofile_limit3200065535
advanced hbase-sitehbase.coprocessor.region.classed

org.apache.hadoop

.security.access.

securebulkloadendpoing

advanced hbase-sitehstore blocking storefiles10500
advanced hbase-sitehbase.bucketcache.ioengineoffheap
advanced hbase-site

hbase.bucketcache.percentage.

in.combinedcache

1
advanced hbase-sitehbase.bucketcache.size10240
custom hbase-sitehbase.client.scanner.timeout.periodundefined240000
custom hbase-sitehbase.hstore.flusher.countundefined20
custom hbase-sitehbase.regionserver.optionalcacheflushintervaundefined36000000
custom hbase-sitehbase.regionserver.regionSplitLimitundefined1
custom hbase-sitehbase.regionserver.thread.compaction.largeundefined8
custom hbase-sitehbase.regionserver.thread.compaction.smallundefined5
custom hbase-sitehbase.snapshot.master.timeout.millisundefined1800000
custom hbase-sitehbase.snapshot.timeout.millisundefined1800000
custom hbase-sitehbase.zookeeper.property.tickTimeundefined6000

参考:

HBase写入报错:org.apache.hadoop.hbase.RegionTooBusyException: Above memstore limit_没有格子衬衫的程序员的博客-CSDN博客

 HBase MEMSTORE 调优及原理

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐