HBase内存配置及JVM优化
前言
本文从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. |
-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优化的更多相关文章
- tomcat内存配置(二)
Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对JavaJVM有关内存方面的知识进 ...
- 从内存泄露、内存溢出和堆外内存,JVM优化参数配置参数
内存泄漏 内存泄漏是指程序在申请内存后,无法释放已申请的内存空间,无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费.内存泄漏最终会导致OOM. 造成内存泄漏 ...
- JVM内存模型和性能优化 转
JVM内存模型和性能优化 JVM内存模型优点 内置基于内存的并发模型: 多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于 ...
- JVM优化-JVM参数配置
配置方式: java [options] MainClass [arguments] options - JVM启动参数. 配置多个参数的时候,参数之间使用空格分隔. 参数命名: 常见为 -参数名 参 ...
- Hbase 参数配置及优化
From:http://www.open-open.com/lib/view/open1346684547787.html 接触hbase已有半年的时间,查了很多资料,也参考了很多别人心得,也希望把自 ...
- java架构之路-(JVM优化与原理)JVM之G1回收器和常见参数配置
过去的几天里,我把JVM内部的垃圾回收算法和垃圾回收器.还剩下最后一个G1回收器没有说,我们今天数一下G1回收器和常见的参数配置. G1回收器 G1 (Garbage-First)是一款面向服务器的垃 ...
- Java虚拟机内存基础、垃圾收集算法及JVM优化
1 JVM 简单结构图 1.1 类加载子系统与方法区 类加载子系统负责从文件系统或者网络中加载 Class 信息,加载的类信息存放于一块称 为方法区的内存空间.除了类的信息外,方法区中可能还会存放 ...
- JBOSS最大连接数配置和jvm内存配置
一.调整JBOSS最大连接数. 配置deploy/jboss-web.deployer/server.xml文件 . <Connector port="80 ...
- JVM内存配置
JVM内存主要分为两个部分,分别是PermanentSapce和HeapSpace. PermantSpace主要负责存放加载的Class类级对象如class本身,method,field等反射对象, ...
随机推荐
- uni-app p-table下时间转换的问题
问题描述: 从后台获取时间戳,转成日期格式,出现NaN的问题 uni的p-table插件 解决思路
- Beta冲刺随笔——测试
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 团队进行Alpha冲刺 作业正文 正文 其他参考文献 无 ...
- 【DKNN】Distilling the Knowledge in a Neural Network 第一次提出神经网络的知识蒸馏概念
原文链接 小样本学习与智能前沿 . 在这个公众号后台回复"DKNN",即可获得课件电子资源. 文章已经表明,对于将知识从整体模型或高度正则化的大型模型转换为较小的蒸馏模型,蒸馏非常 ...
- [翻译自官方]什么是RDB和AOF? 一文了解Redis持久化!
概述 本文提供Redis持久化技术说明, 建议所有Redis用户阅读. 如果您想更深入了解Redis持久性原理机制和底层持久性保证, 请参考文章 揭秘Redis持久化: http://antire ...
- 转:为什么说Python是最值得学习的编程语言
老猿作为一个老程序员,研究生毕业后就没有这么用心的学过一门新的语言,而今年4月开始学Python以来,疯狂的迷上了它,有时很想写一篇为什么要学Python的文章,可一直懒没动笔,今天看到博友" ...
- PyQt(Python+Qt)学习随笔:QTreeWidget的columnCount属性
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 树型部件中的每个项有一个或多个文字标签或其他装饰符(如图标),这些内容每个显示为一列.QTreeWi ...
- python 读取excel表格内不同类型的数据
不同类型数据对应值: #coding=utf-8 import os import xlrd from datetime import datetime,date newparh = os.chdir ...
- 2、tensorflow 变量的初始化
https://blog.csdn.net/mzpmzk/article/details/78636137 关于张量tensor的介绍 import tensorflow as tf import n ...
- 团队项目6——Alpha阶段项目复审
复审团队 广东靓仔六强选手 复审员 钟俊豪(3118005122) 复审内容 小组名称和链接 优点 缺点&Bug报告 最终排名 代码敲不队https://www.cnblogs.com/pip ...
- 《Eroico》关卡与操作设计
操作设计: 没有给明操作教程,操作全靠蒙,只有改建的位置可以看到. 但游戏的难度并没有给玩家适应操作感,随着难度提升怪物血量增厚,但怪物并没有僵直英雄却有僵直.第一个小猫妖便给了玩家一个痛击. 方向键 ...