1、zookeeper.session.timeout(默认时间是:3分钟(180000ms))

有时候正在运行的regionserver会因为网络或者其他问题,造成不按照规定时间报活;

如果regionserver在规定的时间内没有响应,那么zookeeper会把这个regionserver移除

如果一旦移除了,那么hmaster就会收到通知,这时候就会把以前regionserver上负责的一些region重新balance,也就是给迁移走,由其他的regionserver管理;

Zookeeper.session.timeout这个参数就是控制合适把出故障的hbase进行failover;

Zookeeper.session.timeout这个参数也要根据现有的情况去调节,那么效果是不同的:

比如说既然出故障了,调低timeout的时间的确是可以加速failover,特别是针对线上的hbase,因为既有可能会做批量的查询,那很难保证客户要查询的基于rowkey的数据不再坏掉的regionserver上,所以快速点也是有好处的;

但是时间也不能太短,比如说我们把超时时间设置成50秒,50秒之后,zookeeper把regionserver移除了。然后hmaster也开始做balance操作。

但是出问题的regionserver被运维用WAL日志修复了之后,那就会造成负载不均衡的现象

2、Hbase.regionserver.handler.count(默认值:10)

这个参数的意思是:RegionServer的请求处理IO线程数

这个参数的设置是和内存有关系的,也要考虑当前系统的一个现状去设置的

并不是值越大越好的,这是因为我们要考虑到内存现状和当前操作的场景;

假如当前内存比较充足,而且还是要做大数据量操作(比如全表的扫描scan或者需要一次put大量的数据),那就嘴好把线程数量设置的小一些。这样反倒效率高而且不会出现内存泄露的事情

如果是ReigonServer的内存比较紧张的场景。较多的IO线程,就适用于单次请求内存消耗低,TPS(每秒执行的事务数量)请求高的场景

所以说,这个数量不是越高越好的

3、Hbase.hregion.max.filesize(默认256M)

单个region可存储的最大空间,如果存储的数据超过这个大小就会分裂(split),分裂成两个小的region。

这个值也是需要慎重考虑,要考虑一下现有情况去做调节;

(小)

如果把Hbase.hregion.max.filesize这个值调节的小,那么以后region做分裂速度会很快,而且如果region小的话,那么region内部的storefile也很小,这样我们做compact操作的时候,占用很低,而且速度快

但是如果Hbase.hregion.max.filesize这个值调节的小,也意味着region的分裂和compact操作会很频繁,这就会影响集群响应时间,会导致集群的响应时间波动很大,这是一个不好的事情,甚至会导致一些bug出现;

(大)

Hbase.hregion.max.filesize这个值调节的太大了也不合适,因为这样在region分裂和compact的时候,是一种沉重的而且是长时间的IO操作,会导致Hbase的读写操作出现卡顿现象,所以影响也非常大。而且如果Hbase.hregion.max.filesize值很大,意味着region很大,region很大意味着storefile很大,那么在compact的时候,还可能内存不够,导致OOM;

这两点都有缺点,但是怎么避免?

因为这个compact操作是必须的,是无法避免的。所以我们可以从region的分裂着手,

让region的分裂变成手动的,然后在某一个时间点,就是系统负荷最低的时间,我们在做一次region的分裂

如果让region的分裂变成手动的?

我们首先要把Hbase.hregion.max.filesize调整一个非常大的值,也就是说regionserver不可能达到的值,比如说200G

这样,这个region就永远不会自动分裂了。

然后在一个低谷的时间,我们使用hbase的shell里面一个工具:RegionSplitter

hbase org.apache.hadoop.hbase.util.RegionSplitter 表名字 HexStringSplit -c 要分割的区域数量 -f 列族名字

4、hbase.regionserver.global.memstore.upperLimit(默认值0.4)

5、hbase.regionserver.global.memstore.lowerLimit(默认值0.35)

上面这两个就是纯内存的操作。

upperLimit:

这个是调节我们memstore大小的,先说upperLimit,这个参数是防止因为占用内存过大,在你flush的时候出现OOM

因为如果这个upperLimit过大的话,在flush的时候,会把内存所有的数据放到一个队列里面,用生产者消费者的模式往磁盘上刷来释放memstore占用的内存,如果这时候消费者速度跟不上,就会出现积压消息过多,严重了就会OOM

所以我们限制这个upperLimit,在memstore占用内存达到推内存的upperLimit的时候,就强制flush,并且会blobk住写操作,来释放memstore占用的内存,避免出现OOM这样严重的问题

lowerLimit:

和upperLimit差不多,只不过lowerLimit会在memstore达到heap内存的lowerLimit值得时候,会做flush释放内存,但是并不是释放所有的,而是去找占用内存最大的那个region

去做flush操作

这里还要说一个参数:

Hfile.block.cache.size(默认值是0.2)

HBase上Regionserver的内存分为两个部分,一部分作为Memstore,主要用来写;另外一部分作为BlockCache,主要用于读

BlockCache大小+memstore大小 绝对不能大于等于heap的80%大小,否则hbase就瘫痪了,不能启动了;

所以我们在调节upLimit和lowerLimit的时候也要考虑到Hfile.block.cache.size;

到时候就看你这个hbase的库是写操作重 还是 读操作重

6、Hbase.hregion.memstore.block.multiplier(默认值2)

有一个参数:hbase.hregion.memstore.flush.size (默认值64M),每次hbase做完更新操作之后都会检查这个参数,如果当前region的memstore大于hbase.hregion.memstore.flush.size (默认值64M)这个值得时候,就会做flush操作;

而Hbase.hregion.memstore.block.multiplier(默认值2)这个参数就是为了防止:突然出现大的put操作,导致一些问题,比如OOM

比如:

本来我们设置的hbase.hregion.memstore.flush.size =100M , 但是突然之间要put数据,大小是310M,那么这个310M已经超出了hbase.hregion.memstore.flush.size =100M的3倍,所以此时需要Hbase.hregion.memstore.block.multiplier(默认值2)这个参数做一下最大限制 , 意思是说:如果memStore大小增加到Hbase.hregion.memstore.block.multiplier(默认值2)这个值得时候,hbase就会block住所有的请求操作,然后开始做flush操作

7、hbase.hstore.blockingStoreFiles(默认值是7)

之前说过,hbase在region下的store里面的storefile过多的时候,因为会影响读取的速度,所以会做compaction操作,但是这个storeFile到底怎么算是过多?

就是由hbase.hstore.blockingStoreFiles(默认值是7)这个参数控制的。当storefile的数量达到指定的值后,hbase会block主读写操作,然后开始compaction;

但是尽量不要把这个值设置的非常小,因为这样会导致频繁的compaction操作,因为会block住读写操作,是跟得不偿失的一种行为

8、hbase.hregion.memstore.mslab.enabled

· 是否开启mslab方案,减少因内存碎片导致的Full GC,提高整体性能

· 线上配置:true

· 默认配置: true

9、尽量不要超过2个列族(Column Family)

首先说,我们查询,按照rowkey做查询的时候,具体的数据是存在列族上面的,但是列族的数据是由region去做管理的,region又是由regionServer负责的,所以如果一个hbase数据库的列族特别多的话,读取写操作都是比较占用IO的操作;

而且hbase很难保证存在2个以上的列族的时候会处理不发生问题的,这也是hbase不足的地方,另外就是在做flush操作的时候,列族之间也会有关联的,那么可能会导致临近的列族受到牵连,也会被flush,导致更沉重的io操作

10、避免CMS concurrent mode failure

在hbase做GC的时候,我们采用CMS方式做回收是没问题的,也是正确方式。但是这个CMS 这种标记回收默认是当老年代内存达到90%的时候,开始做回收;

但是可以想象一下这样的场景:

假如此时老年代内存达到了90%,老年代开始CMS的并发收集,此时年轻代还在不断的把对象晋升到老年代,那么这个时候就很可能出现,老年代的CMS还没完成标记,老年代的空间就满了,那么这个时候就会出现比较严重的full GC ,停掉所有正在运行的线程,然后以单线程的方式去做回收,这个时间是很漫长的;

所以我们最好用:-XX:CMSInitiatingOccupancyFraction=N(默认90)这个参数去控制,不要把老年代的GC设置的这么高,调节到60%就可以

11、客户端在写数据时候的优化

我们操作客户端向表put的数据时候,默认是一条put一次的,这种方式会有更多的io,是降低性能的操作,所以我们可以命令客户端去做批量的put

就是在代码中加入:

new HTable.setAutoFlush(false);

这样就是说:当Put填满客户端flush缓存时,才发送到服务端

12、在scan表的时候,尽量以少的RPC请求去获取更多的数据

Scan的操作是是一次读取一条的,每次读取的时候,都是一次RPC的请求。那么我们可以让每次的RPC请求读取到更多的数据。

所以可以在代码中写:(scan.setCaching(50);)

这样就可以一次RPC,返回更多的数据,效率是有所提升的

13、在scan的时候要指定具体列族

scan时指定需要的Column Family,可以减少网络传输数据量,否则默认scan操作会返回整行所有Column Family的数据。

scan.addFamily()