如果一个节点有过多的读写操作,会造成热点问题,HBase可能会因为Zookeeper的连接超时而关掉该节点,一个好的策略是将表预分割为固定数量的区域(region),并且这些区域均匀地分布在所有的服务器(regionserver)上,然后让HBase的自动分割功能来处理后面不断增加的数据。
RegionSplitter提供三个用于Pre-splitting的工具:HexStringSplit、UniformSplit、SplitAlgorithm。
HexStringSplit
row key是十六进制的字符串(hexadecimal ASCII)作为前缀的时候
HexHash(prefix)作为row key的前缀,其中Hexhash为最终得到十六进制字符串的hash算法
#方式一
create 'mytable', { NAME => 'info', COMPRESSION => 'snappy' }, {NUMREGIONS => 60, SPLITALGO => 'HexStringSplit'}
#方式二
hbase org.apache.hadoop.hbase.util.RegionSplitter mytable HexStringSplit -c 10 -f f1
UniformSplit
row key是字节数组arbitrary bytes的时候
某个hbase的表查询只是以随机查询为主,可以用UniformSplit的方式进行,按照原始byte值(从0x00~0xFF)右边以00填充。以这种方式分区的表在插入的时候需要对rowkey进行一个技巧性的改造, 比如原来的rowkey为rawStr,则需要对其取hashCode,然后进行按照比特位反转后放在最初rowkey串的前面
create 'tracker_total_live_active_fact', 'info',{NUMREGIONS => 15, SPLITALGO => 'UniformSplit'}
rowkey设计:
public static void main(String[] args) throws Exception {
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "hadoop1");
conf.set("hbase.zookeeper.property.clientPort", "2181");
HConnection connection = HConnectionManager.createConnection(conf);
HTableInterface table = connection.getTable("huanggang");
for (int i=1; i< 6553500; i++) {
byte[] rowKey = Bytes.add(Bytes.toBytes(Integer.reverse(Integer.valueOf(Integer.valueOf(i).hashCode()))), Bytes.toBytes(i));
System.out.println(rowKey);
Put put = new Put(rowKey);
put.add("f".getBytes(), "col1".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));
put.add("f".getBytes(), "col2".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));
put.add("f".getBytes(), "col3".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));
put.add("f".getBytes(), "col4".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));
put.add("f".getBytes(), "col5".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));
put.add("f".getBytes(), "col6".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));
table.put(put);
}
table.flushCommits();
table.close();
}
SplitAlgorithm
SplitAlgorithm是一个接口,需要开发人员自己实现相应的分隔策略
SplitAlgorithm splitAlgo = new SplitAlgoInstance(conf, splitClass);//实例化自定义splitAlgorithm对象。
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class FileSplit implements SplitAlgorithm {
// public static final String SPLIT_KEY_FILE = "split-keys";
private String splitKeyFile;
public FileSplit(String splitKeyFile) {
this.splitKeyFile = splitKeyFile;
}
@Override
public byte[] split(byte[] start, byte[] end) {
return null;
}
@Override
public byte[][] split(int numberOfSplits) {
BufferedReader reader = null;
try {
List<byte[]> regions = new ArrayList<byte[]>();
//一行一行读
reader = new BufferedReader(new FileReader(splitKeyFile));
String line;
while ((line = reader.readLine()) != null) {
// System.out.println(line);
if (line.trim().length() > 0) {
regions.add(Bytes.toBytes(line));
}
}
return regions.toArray(new byte[0][]);
} catch (IOException e) {
throw new RuntimeException("Error reading splitting keys from " + splitKeyFile, e);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (reader != null) reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public byte[] firstRow() {
return null;
}
@Override
public byte[] lastRow() {
return null;
}
@Override
public void setFirstRow(String s) {
}
@Override
public void setLastRow(String s) {
}
@Override
public byte[] strToRow(String input) {
return null;
}
@Override
public String rowToStr(byte[] row) {
return null;
}
@Override
public String separator() {
return null;
}
@Override
public void setFirstRow(byte[] bytes) {
}
@Override
public void setLastRow(byte[] bytes) {
}
}
自定义分区
create 'mytable', 'colfam1', {SPLITS => ['ROW-100','ROW-200','ROW-300','ROW-400']}
还可以指定分区文件
create 'mytable', { NAME => 'dim', COMPRESSION => 'snappy' }, { NAME => 'fact', COMPRESSION => 'snappy' },SPLITS_FILE => 'splits.txt'
分区文件
00|
01|
02|
03|
04|
05|
06|
07|
08|
09|
10|
11|
12|
13|
14|
15|
16|
17|
18|
19|
20|
21|
22|
23|
24|
这里是以一天的24小时作为前缀来设计rowkey的
参考站点: