HBase优化指南

Hbase2x 增删改查 scala版中,有介绍HBase1.2.x增删改查的api文档,但仅仅了解还是不够,在不同的读写业务场景中,必须做出适当优化,才能满足业务需求。本文首先讲解HBase缓存机制,并针对服务端(server)和客户端(client)进行调优说明。

一、HBase缓存机制

HBase由master和regionserver组成,master用来管理regionserver并进行负载均衡,regionserver用来管理当前节点的region并响应客户端读写请求。

1. 写缓存

regionserver包括N个memstore和一个blockcache,其中memstore用来写缓存,blockcache用来度缓存。regionserver给每个region都分配一个memstore,数据写入会先预先Log(WAL机制开启时),然后写入memstore,当达到memstore设定的阈值(hbase.hregion.memstore.flush.size),会触发flush操作溢写到storefile;或达到全局性溢写触发阈值(heapsize * hbase.regionserver.global.memstore.upperLimit),会强行启动flush进程,从最大memstore开始flush至storefile。当一个region内storefile超过设定阈值(hbase.hstore.compaction.min),则启动compact进程,把小的storefile合并为大的storefile。当region越来越大,达到阈值(hbase.hregion.max.filesize),则自动split。

2. 读缓存

读请求先到memstore中查数据,查不到就到blockcache中查,再查不到就会到磁盘上读,并把读的结果放入blockcache。由于blockcache是一个LRU,因此blockcache达到上限(heapsize * hfile.block.cache.size)后,会启动淘汰机制,淘汰掉最老的一批数据。

二、服务端调优

1. 参数配置

1.1 关闭自动split和compact

hbase.hregion.max.filesize 配置region大小,默认10G。region的大小与集群支持的总数据量有关系,如果总数据量小,则单个region太大,不利于并行的数据处理,如果集群需支持的总数据量比较大,region太小,则会导致region的个数过多,导致region的管理等成本过高。一般提供在线服务的hbase集群均会弃用hbase的自动split,转而自己管理split。

hbase.hstore.blockingStoreFiles HStore的storeFile的文件数大于配置值,则在flush memstore前先进行split或者compact,除非超过hbase.hstore.blockingWaitTime配置的时间,默认为7,可调大。

1.2 处理IO线程数

hbase.regionserver.handler.count 处理RPC的线程数量,默认值:10,根据并发可以设置成80-100-120

1.3 读缓存设置

hfile.block.cache.size 默认值0.25,regionserver的block cache的内存大小限制,在偏向读的业务中,可以适当调大该值,需要注意的是hbase.regionserver.global.memstore.upperLimit的值和hfile.block.cache.size的值之和必须小于0.8。

2. 建表配置

2.1 合理设置预分区及Rowkey

2.1.1 预分区设置

当一个region的数据达到一定量时,hbase会自动开始split,split的过程中会短暂下线region,可能导致请求超时。我们可以预先创建好一定数量的region 来避免hbase自动split情况的发生。

预先创建好多个分区后,应当将rowkey离散化,让数据尽可能均衡的分部在各个region上。可使用hbase内置的算法创建,在hbases shell 下执行:

 create 'test_lee',{NAME=>'f',BLOCKSIZE=>'16384',BLOCKCACHE=>false}, {NUMREGIONS=>10,SPLITALGO=>'HexStringSplit'},OWNER=>'lee'

2.1.2 rowkey长度

建议是越短越好,不要超过16个字节。在HBase中,一个具体的值由存储该值的行键、对应的列(列族:列)以及该值的时间戳决定。HBase中索引是为了加速随即访问的速度,索引的创建是基于“行键+列族:列+时间戳+值”的,如果行键和列族的大小过大,甚至超过值本身的大小,纳闷将会增加索引的大小。并且在HBase中数据记录往往非常之多,重复的行键、列将不但使索引的大小过大,也将加重系统的负担。

2.1.3 rowkey离散化

rowkeyHash= org.apache.hadoop.hbase.util.MD5Hash.getMD5AsHex(Bytes.toBytes("rowkey"));

或者

rowkeyHash1= rowKeyHash.substring(0,8)+rowkey;

2.2 设置最大版本数、存储生命期和压缩格式

2.2.1 设置最大版本数

不推荐设置比较大的最大版本数,会导致storefile大,占用比较多的资源。

 create 'test_lee',{NAME=>'f',BLOCKSIZE=>'16384',BLOCKCACHE=>false,VERSIONS=>5}, {NUMREGIONS=>10,SPLITALGO=>'HexStringSplit'},OWNER=>'lee'

2.2.2 设置生命周期

通过设置生命周期,过期数据将被自动清除。

{NAME=>'f',BLOCKSIZE=>'16384',BLOCKCACHE=>false,VERSIONS=>5,TTL=>86400}, {NUMREGIONS=>10,SPLITALGO=>'HexStringSplit'},OWNER=>'lee'

2.2.3 设置压缩格式

开启lzo或者snappy压缩,压缩会消耗一定的CPU,但是,磁盘IO和网络IO将获得极大的改善,大致可以压缩4~5倍。

{NAME=>'f',BLOCKSIZE=>'16384',BLOCKCACHE=>false,VERSIONS=>5,TTL=>86400,COMPRESSION=>'SNAPPY'}, {NUMREGIONS=>10,SPLITALGO=>'HexStringSplit'},OWNER=>'lee'

如果使用hbase api,则如下

def createTable(tableName: String, family: Array[String],liveTime:Int) {

val admin = connection.getAdmin

val name: TableName = TableName.valueOf(tableName)

val desc: HTableDescriptor = new HTableDescriptor(name)

for (f <- family) {

// 设置列压缩格式

val hColumnDescriptor=new HColumnDescriptor(f).setCompressionType(Algorithm.SNAPPY)

// 设置blockcache大小

hColumnDescriptor.setBlocksize(16384)

// 设置列簇的生命周期

hColumnDescriptor.setTimeToLive(liveTime)

// 设置最大版本数

hColumnDescriptor.setMaxVersions(5)

desc.addFamily(hColumnDescriptor)

}

if (!admin.tableExists(name)) {

admin.createTable(desc)

}

}

三、客户端调优

1. 自动flush设置

默认是开启的,可以关闭自动flush,批量提交。

hbase 1.x以前版本 api:

HTable.setAutoFlushTo(false)

hbase 1.x以后版本 api:

// 设置客户端写buffer大小,达到阈值则flush

val params = new BufferedMutatorParams(name).writeBufferSize(4*1024*1024)

2. WAL设置

当数据被写入时会默认先写入Write-ahead Log(WAL)。WAL中包含了所有已经写入Memstore但还未Flush到HFile的更改(edits)。在Memstore中数据还没有持久化,当RegionSever宕掉的时候,可以使用WAL恢复数据。

可以在服务端修改hbase-site.xml配置hbase.regionserver.hlog.enabled设为false即可关闭(全局表),但不建议。一般在客户端修改设置。

hbase 1.x以前版本 api:

HTable.setAutoFlushTo(false)

hbase 1.x以后版本 api:

put.setDurability(Durability.SKIP_WAL)

3. Compression压缩

客户端和服务端一样可以修改,hbase 1.x和hbase 2.x没有区别,如下。

table.addFamily(new HColumnDescriptor(CF_DEFAULT).setCompressionType(Algorithm.SNAPPY))

4. 批量读写

通过批量读写,hbase 1.x以前版本 api如下:

HTable.put(List<Put>)

HTable.get(List<Get>)

hbase 1.x以后版本 api如下:

Mutator.mutate(gets)
Mutator.mutate(puts)

5. 缓存查询

scan.setCacheBlocks(true)

scan.setCaching(500)

参考资料

https://blog.csdn.net/baymax_007/article/details/81606683

https://blog.csdn.net/xiefu5hh/article/details/52853881

https://blog.csdn.net/yx_keith/article/details/79138974 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值