天天看点

Hbase 学习(五) 调优

当我们往hbase写入数据,它首先写入memstore当中,当menstore的值大于hbase.hregion.memstore.flush.size参数中设置的值后,就会写入硬盘。

在hbase-env.sh文件中,我们可以设置hbase_opts或者hbase_regionserver_opts,后者只影响region server进程。

《hbase权威指南》推荐了上述的写法,下面是从网上搜的,原书中为什么要这么设置的解释真心看不懂。

-xmx8g -xms8g –xmn128m :最大堆内存8g,最小堆内存8g,新生代内存-xmn128m。

-xx:+useparnewgc : 设置对于新生代的垃圾回收器类型,这种类型是会停止java进程,然后再进行回收的,但由于新生代体积比较小,持续时间通常只有几毫秒,因此可以接受。

-xx:+useconcmarksweepgc :设置老生代的垃圾回收类型,如果用新生代的那个会不合适,即会导致java进程停止的时间太长,用这种不会停止java进程,而是在java进程运行的同时,并行的进行回收。

-xx:cmsinitiatingoccupancyfraction :设置cms回收器运行的频率,避免前两个参数引起java进程长时间停止,设置了这个之后,不需要停止java进程,但是会提高cpu使用率。

最后两句是输出详细的日志。

memstore-local allocation buffer,是cloudera在hbase 0.90.1时提交的一个patch里包含的特性。它基于arena allocation解决了hbase因region flush导致的内存碎片问题。

<b>mslab的实现原理</b>(对照arena allocation,hbase实现细节):

memstorelab为memstore提供allocator。

创建一个2m(默认)的chunk数组和一个chunk偏移量,默认值为0。

当memstore有新的keyvalue被插入时,通过keyvalue.getbuffer()取得data bytes数组。将data复制到chunk数组起始位置为chunk偏移量处,并增加偏移量=偏移量+data.length。

当一个chunk满了以后,再创建一个chunk。

所有操作lock free,基于cms原语。

<b>优势:</b>

keyvalue原始数据在minor gc时被销毁。

数据存放在2m大小的chunk中,chunk归属于memstore。

flush时,只需要释放多个2m的chunks,chunk未满也强制释放,从而为heap腾出了多个2m大小的内存区间,减少碎片密集程度。

<b>开启mslab</b>

hbase.hregion.memstore.mslab.enabled=true // 开启msalb 

hbase.hregion.memstore.mslab.chunksize=2m // chunk的大小,越大内存连续性越好,但内存平均利用率会降低,要比插入的单元格的数据大一些。 

hbase.hregion.memstore.mslab.max.allocation=256k // 通过mslab分配的对象不能超过256k,否则直接在heap上分配,256k够大了。

直接上图吧,说多了没用。

Hbase 学习(五) 调优

推荐使用snappy,性能最好,但是snappy要单独安装,安装教程等我装成功了,再发一个文档出来吧。

对于实时性要求稳定的系统来说,不定时的split和compact会使集群的响应时间出现比较大的波动,因此建议把split和compact关闭,手动进行操作,比如我们把hbase.hregion.max.filesize设置成100g(major compaction大概需要一小时,设置太大了,compaction会需要更多的时间),major compaction是必须要做的,群里有个网友给数据设置了过期时间,数据被逻辑删除了,但是没有释放硬盘空间,why?没有进行major compaction,最后是手动进行的合并。

在我们设计rowkey的时候,在前面加上随机数,比如0rowkey-1,1rowkey-2,0rowkey-3,1rowkey-4,去前面加上个随机数,就会有负载均衡的效果,但是如果这样做了,某个机器的数据还是比别的机器要多很多,这个怎么办呢?我们可以手动调用move()方法,通过shell或者hbaseadmin类,或者调用unassign()方法,数据就会转移了。