前面我们又说到Phoenxi的一个trouble-shooting,虽然说这篇博文并没有帮笔者解决这个超时问题,其实很简单,因为问题不是这里的超时引起的。笔者将资源放置到Yarn上跑了下,跑了挺久,就出现了OOM,笔者一开始以为是没有问题的,但是刚想完没问题就被打脸了,所以真正的问题不是这里的超时,而是内存崩了(这只是安慰下自己,如果真是内存崩了,为什么本地会不出现,是吧)。这里呢,可以对笔者的这张表做一个性能上的优化,去检测下我们的这个Phoenix的性能优化后,会不会好点。

关于Phoenxi的性能上的优化,无关外呼从四个角度去考虑,首先就是分区,分区目前就有两种,一个是加盐,另一个就是HBase的预分区 split on。其次,我们可以考虑并行处理,最后在考虑要不要压缩一下,比如说用gz或者lzo来试一下。现在呢,我们可以简单的看下。

加盐表

关于加盐表,笔者在大数据框架开发基础之Phoenix基础中有提到加盐表。在密码学中,加盐是指在散列之前将散列内容(例如:密码)的任意固定位置插入特定的字符串。这个在散列中加入字符串的方式称为加盐。其作用是让加盐后的散列结果和没有加盐的结果不相同,在不同的应用情景中,这个处理可以增加额外的安全性。而Phoenix中加盐是指对pk对应的byte数组插入特定的byte数据。

加盐能解决HBASE读写热点问题,例如:单调递增rowkey数据的持续写入,使得负载集中在某一个RegionServer上引起的热点问题。我们加盐的一般写法是这样的:

1
CREATE TABLE table_name (my_key VARCHAR PRIMARY KEY, col VARCHAR) SALT_BUCKETS = 8;

加盐的原理是我们在key的前面加上了一个byte,所加的byte的计算如下:

1
new_row_key = ((byte) (hash(key) % BUCKETS_NUMBER) + original_key

加多少盐合适?

  • 当可用block cache的大小小于表数据大小时,较优的slated bucket是和region server数量相同,这样可以得到更好的读写性能。

  • 当表的数量很大时,基本上会忽略blcok cache的优化收益,大部分数据仍然需要走磁盘IO。比如对于10个region server集群的大表,可以考虑设计64~128个slat buckets。

加盐表需要注意的事

  • 创建加盐表时不能再指定split key。

  • 加盐属性不等同于split key, 一个bucket可以对应多个region。

  • 太大的slated buckets会减小range查询的灵活性,甚至降低查询性能。

Pre-Split

这个就是之前说的HBase预分区,这个相当于手动的指定分区。同样,在构建之初就对表做预分区处理,增加了HBase的并行,可以有效的去提高我们读写效率。和加盐有一个很大的特点就是,我们不会改变rowKey的顺序。

1
2
3
4
5
6
CREATE TABLE table_name (
my_key VARCHAR NOT NULL PRIMARY KEY,
col1 VARCHAR ,
col2 VARCHAR ,
col3 VARCHAR ,
col4 VARCHAR ) SPLIT ON ('col1','col2','col3')

关于加盐表与Pre-Split的比较

这部分笔者还没有进行测试。带笔者测试后在来补充。

多列簇存储

这个就是将相关的列放置在同一个列簇下,这也是利用到HBase的对于不同的列簇进行分开存储的特点,相关性大的放置在同一个列簇下,可以减少数据检索时扫描得数据量。

1
2
3
4
5
6
CREATE TABLE table_name (
info1.my_key VARCHAR NOT NULL PRIMARY KEY,
info1.col1 VARCHAR ,
info1.col2 VARCHAR ,
info2.col3 VARCHAR ,
info2.col4 VARCHAR ) ;

压缩表数据

笔者在使用Hive的时候,使用的是LZO压缩来对数据进行压缩的,在我们的HBase中,同样也可以使用Lzo压缩或者Gz压缩来对数据进行压缩。

1
2
3
4
5
6
CREATE TABLE table_name (
my_key VARCHAR NOT NULL PRIMARY KEY,
col1 VARCHAR ,
col2 VARCHAR ,
col3 VARCHAR ,
col4 VARCHAR ) COMPRESSION='LZO'

构建二级索引

这里关于二级索引的构建,同样可以参考博文大数据框架开发基础之Phoenix基础,因此不做过多的说明好了。

参数调整

除了我们之前做出的调整,我们也可以在配置中去做相关的调整。一般调整的参数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<property>
<name>index.builder.threads.max</name>
<value>128</value>
<description>为主表更新操作建立索引的最大线程数(Default:10)</description>
</property>
<property>
<name>index.builder.threads.keepalivetime</name>
<value>3600</value>
<description>为主表更新操作建立索引的线程的超时时间(Default:60)</description>
</property>
<property>
<name>index.writer.threads.max</name>
<value>128</value>
<description>将索引写入索引表的最大线程数(Default:10)</description>
</property>
<property>
<name>index.writer.threads.keepalivetimex</name>
<value>3600</value>
<description>将索引写入索引表的线程的超时时间(Default:60)<description>
</property>
<property>
<name>hbase.htable.threads.max</name>
<value>250000000</value>
<description>索引表写入数据的最大线程数(Default:2 147 483 647)</description>
</property>
<property>
<name>hbase.htable.threads.keepalivetime</name>
<value>3600</value>
<description>索引表写入数据的线程的超时时间(Default:60)<description>
</property>
<property>
<name>index.tablefactory.cache.size</name>
<value>128</value>
<description>缓存10个往索引表写数据的线程(Default:10)</description>
</property>