您的位置:首页 > 其它

优化hbase的查询优化-大幅提升读写速率(转)

2015-03-03 08:10 316 查看
问题导读:

1.本文通过什么方法优化查询效率的?

2.如何增大RPC数量?

3.如何调整hbase内存?




环境:suse 8G内存,8核,12T磁盘

hbase master 占一台,其他7台作为hbase的region server

注意:此处不讨论hadoop

情景

我们有7亿的数据,需要做查询操作,需要从1.7亿的表中查找一个字段,并写入到7亿数据的表中。

这里为了描述方便,将7亿数据的表称为:A表,1.7亿数据的表称为B表。

在初期,我们采用的逻辑是:将A表中的数据读取一行,根据其中的某个字段去组织一个GET,然后

立刻提交,从B表取得要查询的字段的值,组织成一个PUT,并提交到A表。

那么这么做的话,完全发挥不出hbase的效率,因为每个get之间它的key不一定连续,或者说是在同一范围

而hbase的服务端会根据每个请求去加载数据到内存,由于请求的块分散,那么数据在内存中的替换过多的频繁。

很有可能和直接读取磁盘数据差不多。

并且采用这种逻辑去处理数据,需要花费时间太多。差不多是10W行读写数据需要40分钟。这对于A表的更新操作

完全是不能接受的。

之后,通过读数据的读取操作进行封装,组织成一个ArrayList<Get> 当到一定程度的时候采取提交。这里还有一个情况就是

有些数据查询不到,那么需要去连接数据库去申请一个自动分配的值,并立刻提交,因为后面可能有请求这个数据。

这就需要分开处理。

在组织GET 列表的时候需要先查询,注意,不要采用table.get去取一个cell的值并判断是否为null来处理。

而是用table.exist(get) 去查询,这是在server-side跑的,效率要高很多。

对于查询不到的值立刻申请值并写入A表。

对于查询的到的,那么就可前面说的组织get 加入到GET列表中,到一定程度再去一次提交,在取到值之后,

在根据将循环数据的记录,将这些组织成put,数量和GET列表一样,不要去具体指定,在循环一次后直接table.put

其他参数修改方面,写的都很多,这里就不提了。

处理速度(取至其中一台服务器中跑的任务):

2011-12-30 17:10:03 Start Write Lines:1700000

2011-12-30 17:14:10 Writed Lines:1700000

2011-12-30 17:14:11 Start Write Lines:1800000

2011-12-30 17:18:21 Writed Lines:1800000

2011-12-30 17:18:22 Start Write Lines:1900000

2011-12-30 17:22:29 Writed Lines:1900000

2011-12-30 17:22:29 Start Write Lines:2000000

2011-12-30 17:26:37 Writed Lines:2000000

2011-12-30 17:26:37 Start Write Lines:2100000

大约是查询,写入速度是4分钟处理10W行数据。

也就是4000/s的速率,较之前的处理方式提升了一个量级



参考:

1、使用bloomfilter和mapfile_index_interval

Bloomfilter(开启/未开启=1/0)
mapfile_index_interval
Exists(0-10000)/ms
Get(10001 - 20000)/ms
0
128
22460
23715
0
0
11897
11416
0
64
13692
14034
1
128
3275
3686
1
64
2961
3010
1
0
3339
3498


测试环境为:单机,规模为10万条数据。随机在10000条数据中有99条存在的情况下。
结论:开启bloomfilter比没开启要快3、4倍。而适当的减少mapfile_index_interval可以提升性能
注意:
在1.9.3版本的hbase中,bloomfilter是不支持的,存在一个bug,可以通过如下的修改加以改正:

(1)、在方法org.apache.hadoop.hbase.regionserver.HStore.createReaders()中,找到如下行

BloomFilterMapFile.Reader reader = file.getReader(fs, false, false);

将其改成

BloomFilterMapFile.Reader reader = file.getReader(fs, this.family.isBloomfilter(), false);

(2)、在方法org.apache.hadoop.hbase.HColumnDescriptor.toString()中,找到如下的代码行

if (key != null && key.toUpperCase().equals(BLOOMFILTER)) {

// Don't emit bloomfilter. Its not working.

continue;

}

将其注释掉

2、hbase对于内存有特别的嗜好,在硬件允许的情况下配足够多的内存给它。

通过修改hbase-env.sh中的

export HBASE_HEAPSIZE=3000 #这里默认为1000m

3、修改java虚拟机属性

(1)、在环境允许的情况下换64位的虚拟机

(2)、替换掉默认的垃圾回收器,因为默认的垃圾回收器在多线程环境下会有更多的wait等待

export HBASE_OPTS="-server -XX:NewSize=6m -XX:MaxNewSize=6m -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode"

4、增大RPC数量

通过修改hbase-site.xml中的

hbase.regionserver.handler.count属性,可以适当的放大。默认值为10有点小

5、做程序开发是注意的地方

(1)、需要判断所求的数据行是否存在时,尽量不要用HTable.exists(final byte [] row) 而用HTable.exists(final byte [] row, final byte[] column)等带列族的方法替代。

(2)、不要使用HTable.get(final byte [] row, final byte [] column) == null来判断所求的数据存在,而是用HTable.exists(final byte [] row, final byte[] column)替代

(3)、HTable.close()方法少用.因为我遇到过一些很令人费解的错误

6、记住HBase是基于列模式的存储,如果一个列族能搞定就不要把它分开成两个,关系数据库的那套在这里很不实用.分成多个列来存储会浪费更多的空间,除非你认为现在的硬盘和白菜一个价。

7、如果数据量没有达到TB级别或者没有上亿条记录,很难发挥HBase的优势,建议换关系数据库或别的存储技术。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: