前言

本文从HBase的内存布局说起,先充分了解HBase的内存区的使用与分配,随后给出了不同业务场景下的读写内存分配规划,并指导如何分析业务的内存使用情况,以及在使用当中写内存Memstore及读内存扩展bucketcache的一些注意事项,最后为了保障群集的稳定性减少和降低GC对于集群稳定性的影响,研究及分享了一些关于HBase JVM配置的一些关键参数机器作用和范例,希望这些不断充实的经验能确保HBase集群的稳定性能更上一个台阶,大家有任何的想法和建议也欢迎一起讨论。

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/3 128G/3*2 80G
blockcache 读缓存 80G*30% 24G
memstore 写缓存 80G*45% 36G

hbase-site.xmll

<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/3 128G/3*2 80G
combinedBlockCache 读缓存设置为整个RS内存的70% 80G*70% 56G
blockcache 主要缓存数据块元数据,数据量相对较小。设置为整个读缓存的10% 56G*10% 6G
bucketcache 主要缓存用户数据块,数据量相对较大。设置为整个读缓存的90% 56G*90% 50G
memstore 写缓存设置为jvm_heap的60% 30G*60% 18G
jvm_heap rs总内存-堆外内存 80G-50G 30G

参数详解

Property Default Description
hbase.bucketcache.combinedcache.enabled true When BucketCache is enabled, use it as a L2 cache for LruBlockCache. If set to true, indexes and Bloom filters are kept in the LruBlockCache and the data blocks are kept in the BucketCache.
hbase.bucketcache.ioengine none Where to store the contents of the BucketCache. Its value can be offheap、heap、file
hfile.block.cache.size 0.4 A float between 0.0 and 1.0. This factor multiplied by the Java heap size is the size of the L1 cache. In other words, the percentage of the Java heap to use for the L1 cache.
hbase.bucketcache.size not set When using BucketCache, this is a float that represents one of two different values, depending on whether it is a floating-point decimal less than 1.0 or an integer greater than 1.0.
  • If less than 1.0, it represents a percentage of total heap memory size to give to the cache.
  • If greater than 1.0, it represents the capacity of the cache in megabytes
  • -XX:MaxDirectMemorySize MaxDirectMemorySize = BucketCache + 1 A JVM option to configure the maximum amount of direct memory available for the JVM. It is automatically calculated and configured based on the following formula: MaxDirectMemorySize = BucketCache size + 1 GB for other features using direct memory, such as DFSClient. For example, if the BucketCache size is 8 GB, it will be -XX:MaxDirectMemorySize=9G.

    hbase-site.xml

    <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运行中读写内存使用情况

    Jmx查询

    http://xxxxxxxx.hadoop.db.com:11111/jmx?qry=Hadoop:service=HBase,name=RegionServer,sub=Server

    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 –Xmx75g 75g 75g
    hbase.regionserver.global.memstore.size 0.22 80g*0.22 = 17.6g 10800044400/1024/1024/1024 ≈ 10G
    hfile.block.cache.size 0.22 80g*0.22 = 17.6g 16763937528 /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级别 当region中任意一个memstore的大小达到了上限
    即>hbase.hregion.memstore.flush.size = 256mb
    小,短暂阻塞写
    region级别 当region中所有的memstore的大小达到了上限
    即>hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size = 8 * 256mb
    小,短暂阻塞写
    regionserver级别 当一个regionserver中所有memstore的大小达到了上限
    即> hbase.regionserver.global.memstore.size * heap_size = 0.22*75g
    大,阻塞regionserver上的所有写请求且时间较长
    regionserver中WAL Log数量达到上限 > hbase.regionserver.maxlogs = 256
    系统会选取最早的一个 WAL Log对应的一个或多个region进行flush
    小,短暂阻塞写
    定期刷新 > hbase.regionserver.optionalcacheflushinterval = 3600000 小,短暂阻塞写
    手动刷新 用户可以通过shell命令flush table 或者flush region name分别对一个表或者一个region进行flush 小,短暂阻塞写
    • Memstore设置总结

    从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的参数进行优化

    hbase-env.sh

    配置项 重要参数详解
    export HBASE_HEAPSIZE=4096 HBase 所有实例包括Master和RegionServer占用内存的大小,不过一般用Master和RegionServer专有参数来分别设定他们的内存大小,推荐值给到4096
    export HBASE_MASTER_OPTS=" -Xms8g -Xmx8g -Xmn1g
    -XX:+UseParNewGC
    -XX:+UseConcMarkSweepGC
    -XX:CMSInitiatingOccupancyFraction=70"
    Master专有的启动参数,Xms、Xmx、Xmn分别对应初始堆、最大堆及新生代大小
    Master小堆,新生代用并行回收器、老年代用并发回收器,另外配置了CMSInitiatingOccupancyFraction,当老年代内存使用率超过70%就开始执行CMS GC,减少GC时间,Master任务比较轻,一般设置4g、8g左右,具体按照群集大小评估
    export HBASE_REGIONSERVER_OPTS="-XX:+UseG1GC
    -Xms75g –Xmx75g
    -XX:InitiatingHeapOccupancyPercent=83
    -XX:G1HeapRegionSize=32M
    -XX:ParallelGCThreads=28
    -XX:ConcGCThreads=20
    -XX:+UnlockExperimentalVMOptions
    -XX:G1NewSizePercent=8
    -XX:G1HeapWastePercent=10
    -XX:MaxGCPauseMillis=80
    -XX:G1MixedGCCountTarget=16
    -XX:MaxTenuringThreshold=1
    -XX:G1OldCSetRegionThresholdPercent=8
    -XX:+ParallelRefProcEnabled
    -XX:-ResizePLAB
    -XX:+PerfDisableSharedMem
    -XX:-OmitStackTraceInFastThrow
    -XX:+PrintFlagsFinal
    -verbose:gc
    -XX:+PrintGC
    -XX:+PrintGCTimeStamps
    -XX:+PrintGCDateStamps
    -XX:+PrintAdaptiveSizePolicy
    -XX:+PrintGCDetails
    -XX:+PrintGCApplicationStoppedTime
    -XX:+PrintTenuringDistribution
    -XX:+PrintReferenceGC
    -XX:+UseGCLogFileRotation
    -XX:NumberOfGCLogFiles=5
    -XX:GCLogFileSize=100M
    Xloggc:${HBASE_LOG_DIR}/gc-regionserver$(hostname)-`date +'%Y%m%d%H%M'`.log
    -Dcom.sun.management.jmxremote.port=10102
    $HBASE_JMX_BASE"
    RegionServer专有的启动参数,RegionServer大堆,采用G1回收器,G1会把堆内存划分为多个Region,对各个Region进行单独的GC,最大限度避免Full GC及其影响

    初始堆及最大堆设置为最大物理内存的2/3,128G/3*2 ≈80G,在某些度写缓存比较小的集群,可以近一步缩小。

    InitiatingHeapOccupancyPercent代表了堆占用了多少比例的时候触发MixGC,默认占用率是整个 Java 堆的45%,改参数的设定取决于IHOP > MemstoreSize%+WriteCache%+10~20%,避免过早的MixedGC中,有大量数据进来导致Full GC

    G1HeapRegionSize 堆中每个region的大小,取值范围【1M..32M】2^n,目标是根据最小的 Java 堆大小划分出约 2048 个区域,即heap size / G1HeapRegionSize = 2048 regions

    ParallelGCThreads设置垃圾收集器并行阶段的线程数量,STW阶段工作的GC线程数,8+(logical processors-8)(5/8)

    ConcGCThreads并发垃圾收集器使用的线程数量,非STW期间的GC线程数,可以尝试调大些,能更快的完成GC,避免进入STW阶段,但是这也使应用所占的线程数减少,会对吞吐量有一定影响

    G1NewSizePercent新生代占堆的最小比例,增加新生代大小会增加GC次数,但是会减少GC的时间,建议设置5/8对应负载normal/heavy集群

    G1HeapWastePercent触发Mixed GC的堆垃圾占比,默认值5
    G1MixedGCCountTarget一个周期内触发Mixed GC最大次数,默认值8
    这两个参数互为增加到10/16,可以有效的减少1S+ Mixed GC STW times

    MaxGCPauseMillis 垃圾回收的最长暂停时间,默认200ms,如果GC时间超长,那么会逐渐减少GC时回收的区域,以此来靠近此阈值,一般来说,按照群集的重要性 50/80/200来设置

    verbose:gc在日志中输出GC情况

    HBase内存配置及JVM优化的更多相关文章

    1. tomcat内存配置(二)

      Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对JavaJVM有关内存方面的知识进 ...

    2. 从内存泄露、内存溢出和堆外内存,JVM优化参数配置参数

      内存泄漏 内存泄漏是指程序在申请内存后,无法释放已申请的内存空间,无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费.内存泄漏最终会导致OOM. 造成内存泄漏 ...

    3. JVM内存模型和性能优化 转

      JVM内存模型和性能优化 JVM内存模型优点 内置基于内存的并发模型:      多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于 ...

    4. JVM优化-JVM参数配置

      配置方式: java [options] MainClass [arguments] options - JVM启动参数. 配置多个参数的时候,参数之间使用空格分隔. 参数命名: 常见为 -参数名 参 ...

    5. Hbase 参数配置及优化

      From:http://www.open-open.com/lib/view/open1346684547787.html 接触hbase已有半年的时间,查了很多资料,也参考了很多别人心得,也希望把自 ...

    6. java架构之路-(JVM优化与原理)JVM之G1回收器和常见参数配置

      过去的几天里,我把JVM内部的垃圾回收算法和垃圾回收器.还剩下最后一个G1回收器没有说,我们今天数一下G1回收器和常见的参数配置. G1回收器 G1 (Garbage-First)是一款面向服务器的垃 ...

    7. Java虚拟机内存基础、垃圾收集算法及JVM优化

      1 JVM 简单结构图   1.1 类加载子系统与方法区 类加载子系统负责从文件系统或者网络中加载 Class 信息,加载的类信息存放于一块称 为方法区的内存空间.除了类的信息外,方法区中可能还会存放 ...

    8. JBOSS最大连接数配置和jvm内存配置

      一.调整JBOSS最大连接数. 配置deploy/jboss-web.deployer/server.xml文件 .       <Connector         port="80 ...

    9. JVM内存配置

      JVM内存主要分为两个部分,分别是PermanentSapce和HeapSpace. PermantSpace主要负责存放加载的Class类级对象如class本身,method,field等反射对象, ...

    随机推荐

    1. VUE中,@click后边( ) 有无括号的区别

      在使用的时候,两种方式结果效果差不多是一样. @click="Login()" @click="Login"而唯一的区别就是,有括号的可以在括号里写传递的参数. ...

    2. PyQt(Python+Qt)学习随笔:QListView的viewMode属性

      老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QListView的viewMode属性用于控制QListView的视图模式,该属性类型为枚举类型Q ...

    3. PyQt(Python+Qt)学习随笔:信号签名(signature of the signal)是什么?

      老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 1.概念解释 函数签名:由函数的参数个数与其类型组成.函数在重载时,利用函数签名的不同即参数个数与类 ...

    4. PyQt学习随笔:重写setData方法截获Model/View中视图数据项编辑的注意事项

      根据<PyQt学习随笔:Model/View中视图数据项编辑变动实时获取变动数据的方法>可以重写从PyQt的Model类继承的setData方法来实时截获View中对数据的更改,但需要注意 ...

    5. APP软件系统测试

      1.功能模块测试 2.交叉事件测试 3.压力测试 存储压力测试 边界压力测试 响应能力压力测试 网络流量测试 4.容量测试 5.安装卸载测试 6.易用性.用户体验测试 7.UI界面测试

    6. 代码审计系列题目CTFD部署(上)

      关于简单部署题目请参考:https://www.cnblogs.com/Cl0ud/p/13783325.html 如果需要进行较复杂部署,可参考本篇 PHP代码审计系列题目的部署,较之前的部署方案, ...

    7. CobaltStrike3.14&3.8安装&中文乱码解决

      工具简介 Cobalt Strike 一款以 Metasploit 为基础的 GUI 框架式渗透测试工具,集成了端口转发.服务扫描,自动化溢出,多模式端口监听,exe.powershell 木马生成等 ...

    8. 学习笔记:Kruscal 重构树

      网上感觉没有什么很详细 + 证明的讲解啊) 前置:Kruskal 求最小生成树. 这个算法可以将一棵树 / 无向连通图重构成一颗有性质的新树. 算法可以解决一些树上瓶颈边权之类的问题,可以把需要持久化 ...

    9. AcWing 339 .圆形数字

      大型补档计划 题目链接 设 \(f[i][j]\) 表示二进制下,数字有 \(i\) 位, \(0\) 的个数 - \(1\) 的个数 \(=\) \(j\) 的方案数 \(f[0][0] = 1;\ ...

    10. uniapp-父组件数组变化同步子组件视图渲染

      项目中子组件封装的是一个picker,父组件需要传数组到子组件中. 如果父组件的数组出现变更,视图中的子组件或许不能直接刷新渲染,需要反复弹起几下才能看到. 试过深度监听,但都没有用,ref也不知道为 ...