HBase中,表会被划分为1...n个Region,被托管在RegionServer中。Region二个重要的属性:StartKey与 EndKey表示这个Region维护的rowKey范围,当我们要读/写数据时,如果rowKey落在某个start-endkey范围内,那么就会定位到目标region并且读/写到相关的数据
当我们只是通过HBaseAdmin指定TableDescriptor来创建一张表时,只有一个region,正处于混沌时期,start-end key无边界,可谓海纳百川。啥样的rowKey都可以接受,都往这个region里装,然而,当数据越来越多,region的size越来越大时,大到 一定的阀值,hbase认为再往这个region里塞数据已经不合适了,就会找到一个midKey将region一分为二,成为2个region,这个过 程称为分裂
如果我们就这样默认地,建表,表里不断地Put数据,更严重的是我们的rowkey还是顺序增大的,是比较可怕的。存在的缺点比较明显。
如果我们所设计的rowkey是单调递增的,这样的rowkey很有可能会全部包含在一个region的范围内,这样的话就会导致只有管理这个region的regionserver工作,而其他的regionserver处于闲置状态,也就是负载不均衡。因此,rowkey的设计和预分区是很有必要的。
我们将随机散列和预分区结合起来,预分区一旦创建好,就会管理自己的startkey和endkey,再配合随机散列对rowkey设计,就能够解决上面这些缺点,从而提高性能。
实现预分区的步骤:
1.取样,根据rowkey的生成策略随机的生成一定数量的rowkey,将取样的结果放进集合当中
2.根据预测表中将会存储的数据大小,设置region的个数。
3.根据region的个数对取样数据进行均匀的分割,比如我们设置的region数量为5,取样的数据个数为1000,那么我们只需要4个临界的rowkey就可以将这些数据分割为5个region,就是这个道理。
按照上述的分区步骤,我们分割出来的分区第一个region是没有上限的,最后一个是没有下限的,剩下的region都维护着自己的startkey和endkey,这样我们就完成了对于表的预分区。
下面是具体的代码实现:
package com.wangl.hadoop.hbase.prepartition;
import java.util.Iterator;
import java.util.TreeSet;
import org.apache.hadoop.hbase.util.Bytes;
public class HashChorWorker {
//随机采样数目
private int baseRecord;
//rowkey生成工具
private RowKeyGenerator rkGen;
//取样时,由取样数目及region数相除得到的数
private int splitKeyBase;
//splitKeys个数
private int splitKeysNumber;
//抽样的计算结果
private byte[][] splitKeys;
public HashChorWorker(int baseRecord, int prepareRegions){
this.baseRecord = baseRecord;
this.splitKeyBase = baseRecord/prepareRegions;
this.rkGen = new RowKeyGenerator();
//需要的split key的个数,如分成10个区,只需要9个分隔符
this.splitKeysNumber = prepareRegions - 1;
}
public byte[][] calSplitKeys(){
splitKeys = new byte[splitKeysNumber][];
//使用treeset保存抽样数据,并排序(定义时指定排序策略)
TreeSet
rows = new TreeSet
(Bytes.BYTES_RAWCOMPARATOR);
for(int i=0;i
rowKeyit = rows.iterator();
int index = 0;
//因为取样数据是排过序的,所以按照被分割的数量每个splitKeysNumber个从抽样数据中取出一个作为region的分割key
while(rowKeyit.hasNext()){
byte[] tempRow = rowKeyit.next();
rowKeyit.remove();
if(pointer!=0 && pointer%splitKeyBase == 0){
if(index < splitKeysNumber){
splitKeys[index] = tempRow;
index ++;
}
}
pointer ++;
}
rows.clear();
rows = null;
return splitKeys;
}
public static void main(String args[]){
HashChorWorker h = new HashChorWorker(100, 3);
byte[][] skeys = h.calSplitKeys();
for(byte[] k : skeys){
System.out.println(Bytes.toString(k));
}
}
}