01
—
选择关闭AutoFlush
默认情况下,AutoFlush是开启的,当每次put操作的时候,都会提交到HBase server,大数据量put的时候会造成大量的网络IO,耗费性能
在大数据量并发下,AutoFlush设置为false,并且将WriteBufferSize设置大一些(默认是2MB)(WriteBufferSize只有在AutoFlush为False情况下起作用)
则需要通过调用HTable.setAutoFlushTo(false)方法可以将HBaseClient写客户端自动flush功能关闭,这样可以批量的将数据写入到HBase中,而不是一条put就执行一次更新!
但是这样也有一个弊端,就是当出现故障的时候,比如宕机事故,缓冲区的数据还没有来得及flush落盘,则会丢失!
02
—
采用批量读写方式
建议使用List<put>来写入hbase数据而不是put。
HBase 通过Put操作来将RowKey信息写入数据,如果在并发度比较高的情况下,频繁的Put会造成网络IO,HBase提供了另一种put操作,可以调用HTable.put(List<Put>)可以批量的写入多条记录,这样就只有一次网络IO操作
同样,HBase也提供一种可以批量读的方式,通过HTable.get(list)方式,可以根据给定的rowkey列表返回多个rowkey结果的集合,这样在通过list方式请求时,只会有一次网络IO,可以减少网络阻塞情况提供网络传输性能!
03
—
启用压缩
HBase创建表时要启用压缩,HBase支持的几种压缩算法分别为:GZIP、LZO、SNAPPY、Zippy.对于几种算法的比较
1)GZIP的压缩率最高,但它是CPU密集型的,对CPU的消耗较多,压缩和解压速度也慢; 2)LZO的压缩率居中,比GZIP要低一些,但是压缩和解压速度明显要比GZIP快很多,其中解压速度快的更多; 3)Zippy/Snappy的压缩率最低,而压缩和解压速度要稍微比LZO要快一些
所以在通常情况下使用Snappy和Zippy压缩算法.
启用压缩的两种方式:
一种是在创建表时指定压缩算法;另一种是创建表后指定压缩算法或者修改压缩算法。
创建表时指定:
代码语言:javascript复制create 'test', {NAME => 'info', VERSIONS => 1, COMPRESSION => 'snappy'}
创建表后修改:
代码语言:javascript复制disable 'test'
代码语言:javascript复制使用alter语句进行修改
代码语言:javascript复制alter 'test', NAME => 'info', COMPRESSION => 'snappy'enable 'test'
最后对表进行major_compact操作,使压缩生效
代码语言:javascript复制major_compact 'test'
04
—
提前评估好集群规模
如果事先不能够合理的评估一个HBase集群规模大小的话,除了对于性能有不好的影响之外,还会降低整个集群的稳定性,比如会出现的状况:客户端响应超时,regionserver宕机;整体集群恢复时间比较长等问题.
如果来评估HBase的集群规模?
首先需要了解应用场景是什么样子的,是一种读更加密集的还是写更加频繁的?因为它涉及到很多方面的考虑.
其次评估好负载情况,区分为读取/写入的负载使用以及预估到的使用模式
对于SLA的要求是什么,如何来量化读写延迟,以及能够对数据的不一致性的容忍程度达到多少?
然后是存储,评估好每天的数据增量是多少,是否要设置好TTL?在整个使用周期中HBase可能会达到的最大数据数据规模
最后是网络;在评估整个HBase集群部署时,网络是一个重要考虑因素,HBase集群通常使用千兆网或者10千兆网,最小配置也应该是千兆网,但是对于一些大的集群来讲使用10千兆网会更加的好一些.因为在底层硬件故障以及在做一些大合并的时候,网络将会是其中的一个瓶颈,region在进行大合并的时候,会进行远程的读写,如果集群故障或者region重新平衡,那么会将网络打满,对于一些SLA要求比较高的场景,显然是不足以支撑的.
那么一个好的环境部署应该是不低于10千兆网络.同时为了保障数据的容错性,使用多机架模式部署可以有效的防止数据单点问题.
05
—
regin太多不一定好
首先从hbase的原理来讲,首先一个regionserver会有多个region组成,那么一个region又包含多个HStore,HStreo由memstore和storefile组成,当client进行写入操作时,会先将数据写入memstore,memstore满了之后将数据flush到storefile,一直到增长到某个阀值,触发compact操作,然后多个storefile会合并为一个Storefile,在这之后还会有storefile split的操作,也就是经常会遇到的region split,使得原先一个region的压力,被分配多个region,统一由master去分配到不同的regionserver中.
那么如果region数量很多,就会生成很多的storefile文件小文件,小文件问题就不再多说了,其次就是会触发hbase的文件合并操作,从而保证HFile的数量在一个合理的范围内,合并操作会造成集群的不稳定,影响集群的性能,region数量越多那么触发合并的操作频次也就越多,也就会直接的影响集群的性能,包括网络IO的,fullgc,regionserver加载异常会报出RegionTooBusyException.
会有哪些因素导致region太多呢?
1). Region的最大值设置的太小
2).split的次数太多
3)预分区设置的不合理
解决方案:
这里有一个关于region数量的计算公式:
代码语言:javascript复制((RS Xmx) * hbase.regionserver.global.memstore.size) / (hbase.hregion.memstore.flush.size * (# column families))
06
—
不建议设置多个列族
我们知道,hbase表中可以设置一个或者多个列族,但是为什么说要把列族数据量不要太多呢?
regionserver管理着多个region,每个region中有多个hstore组成,每个hstore对应表中的column family中的存储,hstore是hbase存储的核心,由memstore和stroefile组成,当memstore满了之后会flush到storefile中.
- region下面的某个storefile过大之后,就会进行split操作.
- 多个列族会形成更多的hfile小文件
- 不同列族会共享region,split操作会导致io增加.
- 一个列族触发flush时,其它列族也会进行flush,导致io压力增加
- 会形成更多小文件,增加hdfs压力
- 查询CF时,会出现跨多个region,查询效率变低
- 多个CF会有多个Memstore,内存占用增大.
07
—
Bloomfilter的合理设置
Bloomfilter过滤器的思想为:当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在
Bloomfilter根据key随机读时,在StoreFile级别进行过滤
Bloomfilter主要用来过滤不存在待检索RowKey或者Row-Col的HFile文件,避免无用的IO操作。它会告诉你在这个HFile文件中是否可能存在待检索的KV,如果不存在,就可以不用消耗IO打开文件进行seek。通过设置Bloomfilter可以提升随机读写的性能,在使用Bloom Filter判断一个元素是否属于某个集合时,会有一定的错误率,不过这种错误率很低. 也就是说除了空间换时间、时间换空间之外,Bloomfilter使用了一种用很低的错误率来减少空间并且快速查询.
Bloomfilter取值有两个,row以及rowcol,需要根据业务来确定具体使用哪种。任何get类型的读取都会Bloomfilter,有如果业务大多数随机查询仅仅使用row作为查询条件,Bloomfilter就需要设置为row,否则如果大多数随机查询使用row cf作为查询条件,Bloomfilter需要设置为rowcol。如果不确定业务查询类型,则可以设置为row
所以在一般的业务场景中
在创建表时开启即可
代码语言:javascript复制create 'test',{NAME=>'INFO,BLOOMFILTER=>'ROWCOL'}
create 'test1',{NAME=>'INFO,BLOOMFILTER=>'ROW'}
08
—
HBase表设计时刻考虑热点问题
热点问题主要原因在于rowkey的设计不合理.
在某个时间段,对HBase的读写请求集中到少数几个region上面,导致这些region所属的regionserver请求量比较大,负载压力增加,而其他regionserver属于空闲状态,一般这种问题就是hbase的rowkey热点问题了.
对于热点问题常用的有效解决办法就是rowkey加盐或者预分区
这里罗列几点rowkey的设计原则:
- rowkey的长度尽量短.
- 散列原则,将数据分散到不同region中.
- 表设计要考虑好热点问题
- rowkey唯一原则,要保证rowkey是唯一的
09
—
避免长时间的GC操作(GC调优)
在HBase服务中影响最大的垃圾回收事件是Java虚拟机要执行一次full gc(一次彻底的垃圾回收)操作,那么此时会导致jvm暂停服务,在这个时候,hbase上面所有的读写操作将会被客户端归入队列中排队,一直等到jvm完成它的gc操作, 在继续的恢复服务.
会导致的问题:
hbase服务长时间暂停会导致HBase服务超时
客户端操作超时,操作请求处理异常.
服务端超时会导致region信息上报异常,导致丢失心跳.
会导致region的重新分配到其它regionserver上
导致RegionServer终止,原有的regionserver 恢复之后,请求zk会告知死亡,并抛出YouAreDeadException异常
如何避免和预防GC超时?
减少堆大小,堆越大,JVM完成GC的时间越长
使用堆外内存,减少GC的时间
使用G1的的GC算法
一些常用的必备参数
代码语言:javascript复制-XX: UseG1GC
-XX: PrintFlagsFinal
-XX: PrintGCDetails
-XX: PrintGCDateStamps
-XX: PrintGCTimeStamps
-XX: PrintAdaptiveSizePolicy
-XX: PrintReferenceGC
10
—
HBase负载均衡调优
正常来讲,一个hbase集群是有多个regionserver组成,这样可以提高hbase集群的并发读写,但是在某些情况下(具体场景具体分析), 应用程序的读可能会落到一个regionserver上面去.那么这样的话 原本的并发优势就不存在了,反而会增加单个regionserver的压力.这是一个很严重的情况,极大概率的会使得这个regionserver挂掉,影响正常的读写请求,造成业务瘫痪,所以说负载不均衡是hbase中的大忌
这里汇总了常见的几种负载均衡的调优方式:
1、观察,出现问题首先要先观察服务的监控和日志信息,观察每个regionserver的qps,看看是否有读写不均衡的现象.
2、rowkey散列化处理,将region分配到不同的regionserver中,可以极大的减少负载不均衡的情况.
3、限流限资源,一旦发现有不均衡情况,可以选择针对用于进行限流或者
罗列几个限制语句
限制用户u1每秒请求10次
代码语言:javascript复制hbase> set_quota TYPE => THROTTLE, USER => 'u1', LIMIT => '10req/sec'
限制用户u1每秒的读请求为10次
代码语言:javascript复制hbase> set_quota TYPE => THROTTLE, THROTTLE_TYPE => READ, USER => 'u1', LIMIT => '10req/sec'
限制用户u1每天的请求量为10M
代码语言:javascript复制hbase> set_quota TYPE => THROTTLE, USER => 'u1', LIMIT => '10M/day'
限制用户u1的写请求量每秒为10M
代码语言:javascript复制hbase> set_quota TYPE => THROTTLE, THROTTLE_TYPE => WRITE, USER => 'u1', LIMIT => '10M/sec'
限制用户u1在操作表t2时,每分钟的请求量为5K
代码语言:javascript复制hbase> set_quota TYPE => THROTTLE, USER => 'u1', TABLE => 't2', LIMIT => '5K/min'
限制用户u1在操作表t2时,每秒的读请求为10次
代码语言:javascript复制hbase> set_quota TYPE => THROTTLE, THROTTLE_TYPE => READ, USER => 'u1', TABLE => 't2', LIMIT => '10req/sec'
删除用户u1在命令空间ns2的请求限制
代码语言:javascript复制hbase> set_quota TYPE => THROTTLE, USER => 'u1', NAMESPACE => 'ns2', LIMIT => NONE
限制在命名空间ns1中每小时的请求为10次
代码语言:javascript复制hbase> set_quota TYPE => THROTTLE, NAMESPACE => 'ns1', LIMIT => '10req/hour'
限制表t1每小时的请求为10T
代码语言:javascript复制hbase> set_quota TYPE => THROTTLE, TABLE => 't1', LIMIT => '10T/hour'
删除用户u1的所有请求限制
代码语言:javascript复制hbase> set_quota TYPE => THROTTLE, USER => 'u1', LIMIT => NONE
显示用户u1在命名空间ns2中的所有限制详情
代码语言:javascript复制hbase> list_quotas USER => 'u1, NAMESPACE => 'ns2'
显示命令空间ns2的所有限制详情
代码语言:javascript复制hbase> list_quotas NAMESPACE => 'ns2'
显示表t1的所有限制详情
代码语言:javascript复制hbase> list_quotas TABLE => 't1'
显示所有限制详情
代码语言:javascript复制hbase> list_quotas
4、选择开启或手动均衡
查看均衡器状态
代码语言:javascript复制balance_switch status
开启均衡器
代码语言:javascript复制balance_switch true
关闭均衡器
代码语言:javascript复制balance_switch false
也可以手动将region移动到其它regionserver中
代码语言:javascript复制move [regionid] [servername]