Hbase 性能优化

 

1. 垃圾回收优化

用户可以通过向hbase-env.sh文件中添加HBASE_OPTS或者HBASE_REGIONSERVER_OPT来设置垃圾回收相关选项,后者仅仅影响region服务器进程,也是推荐的修改方式。

增加新生代大小,  减小新生代垃圾回收次数

-XX:MaxNewSize=8g -XX:NewSize=8g

 

修改垃圾回收策略

-XX:+UseParNewGC 

设置年轻代使用Parallel New Collector策略,这将停止运行Java进程而去清空年轻代堆。与老年代相比年轻代很小,所以这个过程话费时间很短,通常几百毫秒。

 

-XX:+UseConcMarkSweepGC

以上策略如果用于年老代会造成region server几秒钟甚至数分钟停顿,如果停顿时间超过zookeeper会话超时限制,这个服务器会被master认为已经崩溃,并且随后会被抛弃。

这种情况可以使用并行标记回收策略(Concurrent Mark-Sweep Collector, CMS)来缓解, 不同之处在于其工作时试图在不停止运行Java进程的情况下异步并行的完成工作。这种策略将增加CPU的负担,但是却可以避免重写老生代碎片时的停顿--除非发生提示失败,这种失败会迫使垃圾回收暂停运行Java进程并进行内存整理。

 

 

 2. 本地memstore分配缓冲区

由于memstore不断创建和释放内存空间, 就会在年老代Heap上产生孔洞。申请新空间时,由于碎片过多导致没有足够大的连续空间分配,JRE会退回到使用(stop  the world)垃圾回收器,这样会导致其重写整个堆空间并压缩剩余的可用对象。 

 

MSLAB(memstore-local allocation buffers)是许多固定大小的缓冲区,用来存储大小不同的keyvalue实例。当一个缓冲区不能放下一个新加入的keyvalue时,系统就认为这个缓冲区已经占满了,然后创建一个新的固定大小的缓冲区。 一旦这些缓冲区对象被回收,他们将在堆中留下固定大小的孔洞,之后调用固定大小的新对象将会重新使用这些孔洞,这样就不需要JRE停止压缩回收堆内存了。 

 

但是mslab也有一些副作用,比如更加浪费堆空间;使用缓冲区需要额外的内存复制工作,比直接使用keyvalue实例要稍微慢一点

 

配置hbase-site.xml中的 hbase.hregion.memstore.mslab.enabled 默认值 true

 

 

3 压缩

除非存储已经压缩过的内容如JPEG图像,对于其它场景来说,压缩通常会带来较好的性能,因为CPU压缩和解压的时间比从磁盘读取和写入更多数据消耗的时间更短。

算法 压缩比 % 压缩 MB/S 解压 MB/S
GZIP 13.4 21 118
LZO 20.5 135 410
Zippy/Snappy 22.2 172 409

 默认Hbase对文件是没有压缩的, 查看 describe 'tablename'

 

 

4. 优化拆分和合并

通常Hbase是自动处理Region拆分的,一旦它们到了预定的阈值,region将被拆分成两个,之后它们可以接受新的数据并继续增长。 当用户的region大小已恒定速度增长时,region拆分会在同一时间发生,因为同时需要压缩region中的存储文件,这个过程会重写拆分之后的数据,这将引起IO上升,称之为“拆分和并风暴”。

与其依赖自动拆分,不如关闭这个行为调用split和major_compace命令手动拆分。 

 

为防止自动拆分可设置hbase.hregion.max.filesize的值为一个比较大的值,比如100GB。 然后用客户端实现一个调用split()和 majorCompact()的客户端,也可以使用shell交互的调用相关命令,或者使用cron定时的调用它们。

 

另一种方法是创建表时进行预拆分

create 't1', 'f1', SPLITS => ['10', '20', '30', '40']

 

5.负载均衡

master内置了一个叫做均衡器的特性,默认情况下每5分钟(通过hbase.balancer.period设置)运行一次。 一旦均衡器启动,它会尝试均匀分配region到所有region服务器。用户可通过shell的balance_switch命令来更改均衡器的开启或关闭状态。

除了依赖均衡器自动完成工作,用户还可以使用move命令显示地将region移动到另一个region server上。

6. 合并region

当用户删除大量数据并且想减少每个服务器管理的region数量,可以使用merge_region命令合并相邻的region。

7 客户端API最佳实践

禁止自动刷新

put.setAutoFlush(false)

 

使用扫描缓存

scan.setCaching(1000);

 

限定扫描范围

尽量只在一个Family中扫描

 

关闭ResultScanner

一定要在try catch 的 finally 中关闭ResultScanner

 

快缓存用法

scan.setCacheBlocks() 对于那些频繁访问的行,建议使用块缓存

 

优化获取行健的方式当用户仅需要获取需要的行健时,在Scan中用setFilter()方法添加一个带MUST_PASS_ALL的FilterList。FilterList中包含FirstKeyFilter和KeyOnlyFilter两个过滤器。使用以上的组合过滤器将会把发现的第一个keyvalue行健返回给客户端。

 

关闭put上的WAL

当需要存入的数据对准确度要求不是很高时,使用Put的writeToWAL(false)来关闭WAL。

猜你喜欢

转载自oracle-api.iteye.com/blog/2367827