HBase内存配置及JVM优化

前言

本文从HBase的内存布局说起,先充分了解HBase的内存区的使用与分配,随后给出了不同业务场景下的读写内存分配规划,并指导如何分析业务的内存使用情况,以及在使用当中写内存Memstore及读内存扩展bucketcache的一些注意事项,最后为了保障集群的稳定性,减少和降低gc对于集群稳定性的影响,研究及分享了一些关于HBase JVM配置的一些关键参数机器作用和范例。

HBase的内存布局

一台region server的内存使用(如图)主要分为两个部分:

1、jvm内存即我们通常俗称的堆内内存,这块内存区域的大小分配在HBase的环境脚本中设置,在堆内内存中主要有三块内存区域。

  • 20%分配给hbase + regionserver rpc请求队列及一些其他操作
  • 80%分配给memstore + blockcache

2、java direct memory 即堆外内存

  • 其中一部分内存用于HDFS SCR/NIO  操作
  • 另一部分用于堆外内存 bucket cache ,其内存大小的分配同样在hbase的环境变量脚本中实心

读写内存规划

  • 写多读少型规划

在详细说明具体的容量规划前,首先要明确on heap 模式下的内存分布图。

如图,整个RegionServer内存就是JVM所管理的内存,BlockCache用于读缓存,MemStore用于写流程,缓存用户写入KeyValue数据,还有部分用于RegionServer正常RPC请求运行所必须的内存。

步骤原理        计算
jvm_heap系统总内存的2/3128G/3*280G
blockcache读缓存80G*30%24G
memstore        写缓存80G*45%36G

 hbase-site.xml

<property>
<name>hbase.regionserver.global.memstore.size</name>
<value>0.45</value>
</property>
<property>
<name>hfile.block.cache.size</name>
<value>0.3</value>
</property>

  • 读多写少型规划

与 on heap模式相比,读多写少型需要更多的读缓存,在对读请求响应时间没有太严苛的情况下,会开启off heap即启用堆外内存中的bucket cache作为读缓存的补充,如图

 整个RegionServer内存分为两个部分:JVM内存和堆外内存。其中JVM内存中BlockCache和堆外内存BucketCache一起构成了读缓存CombinedBlockCache,用于缓存读到的Block数据,其中BlockCache用于缓存Index Block和Bloom Block,BucketCache用于缓存实际用户数据Data Block。

步骤原理计算
RS总内存系统总内存的 2/3128G/3*280G
combinedBlockCache读缓存设置为整个RS内存的70%80G*70%56G
blockcache主要缓存数据块元数据,数据量相对较小。设置为整个读缓存的10%56G*10%6G
bucketcache主要缓存用户数据块,数据量相对较大。设置为整个读缓存的90%56G*90%50G
memstore写缓存设置为jvm_heap的60%30G*60%18G
jvm_heaprs总内存-堆外内存80G-50G30G

<property>
<name>hbase.bucketcache.combinedcache.enabled</name>
<value>true</value>
</property>
<property>
<name>hbase.bucketcache.ioengine</name>
<value>offheap</value>  #同时作为master的rs要用heap
</property>
<property>
<name>hbase.bucketcache.size</name>
<value>50176</value>  #单位MB。这个值至少要比bucketcache小1G,作为master的rs用heap,那么这里要填<1的值作为从heap中分配给bucketcache的百分比
</property>
<property>
<name>hbase.regionserver.global.memstore.size</name>
<value>0.60</value>  #heap减小了,那么heap中用于memstore的百分比要增大才能保证用于memstore的内存和原来一样
</property>
<property>
<name>hfile.block.cache.size</nname>
<value>0.20</value>  #使用了bucketcache作为blockcache的一部分,那么heap中用于blockcache的百分比可以减小
</property>

hbase-env.sh

export HBASE_REGIONSERVER_OPTS="-XX:+UseG1GC  -Xms30g –Xmx30g -XX:MaxDirectMemorySize=50g"

读写内存的使用情况

在HBase集群运行的过程中,我们需要了解HBase实际情况下的读写内存使用,才能最大化的对配置做出最佳的调整,接下来说下如何查询HBase运行中读写内存使用情况

 memStoreSize代表RegionServer中所有HRegion中的memstore大小的总和,单位是Byte。该值的变化,可以反应出一个RegionServer上写请求的负载状况,可以观察memstoreSize的变化率,如果在单位时间内变化比较抖动,可以近似认为写操作频繁。
blockCacheFree代表block cache中空闲的内存大小。计算方法为:getMaxSize() – getCurrentSize(),单位是Byte,该值反映出当前BlockCache中还有多少空间可以被利用。
blockCacheSize代表当前使用的blockCache的大小。BlockCache. getCurrentSize(),单位是Byte,该值反映出BlockCache的使用状况。
以单台region server配置为例

配置项配置值内存分配值实际使用量
HBASE_REGIONSERVER_OPTS-Xms75g –Xmx75g75g75g
hbase.regionserver.global.memstore.size0.2280g*0.22 = 17.6g10800044400/1024/1024/1024 ≈ 10G
hfile.block.cache.size0.2280g*0.22 = 17.6g16763937528 /1024/1024/1024 ≈ 15.6G
952802568 /1024/1024/1024 ≈ 0.9G

结合单台regionserver 的配置来看,读写缓存都有一定空闲空间,这种情况下可以降低heap size来减少gc的次数和时长,然后我们还需要以群集所有region server的数据来判断该集群的配置是否合理,如果存在读写不均衡和热点情况都会影响不同region间的缓存大小。

Memstore深度解析

  • memstore简介

一张数据表由一个或者多个region组成,在单个region中每个columnfamily组成一个store,在每个store中由一个memstore和多个storefile组成。

 HBase是基于LSM-Tree数据结构的,为了提升写入性能,所有数据写入操作都会先写入memstore(同时会顺序写入WAL),达到指定大小后会对memstore中的数据做次排序后在批量flush磁盘中,此外新写入的数据有较大概率被读取到,因此HBase在读取数据时首先检查memstore中是否有数据缓存,未命中的情况下再去找读缓存,可见memstore无论对于HBase的写入和读取性能都至关重要,而其中memstore flush操作又是memstore最核心的操作。

  • memstore flush操作

从memstore flush的动作来看,对业务影响最大是regionserver级别的flush操作,假设每个memstore大小为256mb,每个region有两个cf,整个regionserver上有100个region,根据计算可知,总消耗内存 = 256mb2100 = 51.2g >> 0.40*80g = 32g ,很显然这样的设置情况下,很容易触发region server级别的flush操作,对用户影响较大。
根据如上分析,memstore的设置大小不仅取决于读写的比例,也要根据业务的region数量合理分配memstore大小,同样的我们对每台regionserver上region的数量及每张表cf的数量上的控制也能达到理想的效果。

  • 堆外内存注意事项

BucketCache的三种工作模式:

  • heap

heap模式分配内存会调用byteBuffer.allocate方法,从JVM提供的heap区分配。
内存分配时heap模式需要首先从操作系统分配内存再拷贝到JVM heap,相比offheap直接从操作系统分配内存更耗时,但反之读取缓存时heap模式可以从JVM heap中直接读取比较快。

  • offheap

offheap模式会调用byteBuffer.allocateDirect方法,直接从操作系统分配,因为内存属于操作系统,所以基本不会产生CMS GC,也就在任何情况下都不会因为内存碎片导致触发Full GC。
内存分配时offheap直接从操作系统分配内存比较快,但反之读取时offheap模式需要首先从操作系统拷贝到JVM heap再读取,比较费时。

  • file

file使用Fussion-IO或者SSD等作为存储介质,相比昂贵的内存,这样可以提供更大的存储容量。

堆外内存的优势

使用堆外内存,可以将大部分BlockCache读缓存迁入BucketCache,减少jvm heap的size,可以减少GC发生的频次及每次GC时的耗时
BucketCache没有使用JVM 内存管理算法来管理缓存,而是自己对内存进行管理,因此其本身不会因为出现大量碎片导致Full GC的情况发生。

堆外内存的缺陷

读取data block时,需要将off heap的内存块拷贝到jvm heap在读取,比较费时,对读性能敏感用户不太合适。

堆外内存使用总结

对于读多写少且对读性能要求不高的业务场景,offheap模式能够有效的减少gc带来的影响,线上的vac集群在开启offheap模式后,GC频次和耗时都能有效降低,但是因为bucketcache 读的性能的问题达不到要求而回退到heap模式。

JVM配置优化及详解

Hbase服务是基于JVM的,其中对服务可用性最大的挑战是jvm执行full gc操作,此时会导致jvm暂停服务,这个时候,hbase上面所有的读写操作将会被客户端归入队列中排队,一直等到jvm完成gc操作, 服务在遇到full gc操作时会有如下影响

  • hbase服务长时间暂停会导致客户端操作超时,操作请求处理异常。
  • 服务端超时会导致region信息上报异常丢失心跳,会被zk标记为宕机,导致regionserver即便响应恢复之后,也会因为查询zk上自己的状态后自杀,此时hmaster 会将该regionserver上的所有region移动到其他regionserver上

如何避免和预防GC超时的不良影响,我们需要对JVM的参数进行优化

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值