HBase调优及优化的20种方式(上)

2022-04-18 18:45:54 浏览数 (1)

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]

0 人点赞