一、分区键设计
分区是解决数据倾斜的有效有段,分区比较简单, 关键在于需要分多少区,比如本项目分六个区形式为
00|
00| 01|
01| 02|
02| 03|
.........
05|
为什么每个分区号要加竖线呢?因为,竖线的值比较大比下线等大,而rowkey分哪个区是需要按位比较的,而且一般分区是0x_ xxxxxx_bbbb 。。。,使用竖线可以将rowkey拦截在分区内
/**
* 创建分区号。类似于 00|,01|,02|,03|,
*/
private static byte[][] getPartions(int regions){
byte[][] bs = new byte[regions][];
for (int i = 0; i < regions; i++) {
String format = new DecimalFormat("00").format(i);
bs[i]= Bytes.toBytes(format+"|");
}
return bs;
}
首先说明一下,为什么返回值是byte[][] ?原因是createTable需要传进去的就是二维数组,因为有多个分区,且没有分区又都是字节数组,所以说,传的是二维的byte数组
void createTable(final HTableDescriptor desc, byte[][] splitKeys) throws IOException;
二、rowkey设计
1、每个项目的rowkey的设计是最核心的,而rowkey的设计往往与业务相关,但是必须要遵循原则:唯一性和散列,一般的形式如下:
随机的分区键(这个为了比较散列,但是真的用random随机时,取数据反而不好取) + 时间戳(保证唯一性)+常用的column和value(加上常用的value可以提高查找的效率)+ 。。。
而分区键的设计一般是采用,使用的后面的value一般是唯一的像身份证号等,hash(常用的value+年月)%总分区数,不过不一定用hash像亦或或者是MD5也行,只要是能使值比较散列即可
思考:为什么选到年月而不是年月日呢?不过这不一定是年月,就本项目而言带年月是最好的,到年月日反而不好
2、就本项目而言设计形式是:0X_133626666677_2017-12-1 12:10_144444455555_180,其中的OX的设计被分装成方法getParId,
分析上面的思考题:
将rowkey最好是均匀分布在多个region,同时又能实现即集中又分散的,比如查询用户一年的数据,或者是一个月的数据,选择到月是最合适的,到年的话,数据太集中,一个用户一年的数据在一个region上,查询一个月时不好查,但是选择到日的话,又太分散,
public static String getPartionKey(String call1,String buildTime,int regions){
// String a = phone.substring(7);
// String b = buildTime.replaceAll("-", "").substring(0, 6);
//
// int i = (a + b).hashCode() % regions;
// return new DecimalFormat("00").format(i);
//取手机号后4位
String last4Num = call1.substring(7);
//取年月
String yearMonth = buildTime.replace("-", "").substring(0, 6);
//采用亦或也可以实现散列
int hashCode = (Integer.parseInt(last4Num) ^ Integer.parseInt(yearMonth)) % regions;
return new DecimalFormat("00").format(hashCode);
}
3、rowkey的创建
使用上面的方法可以获得分区号,在结合0X_133626666677_2017-12-1 12:10_144444455555_180形式创建如下:
/**
* 创建rowkey
* 0X_133626666677_2017-12-1 12:10_144444455555_180
* 常用的字段的顺序也很重要,如果将电话号码和日期换过来的话,查询的时候又会将别人的记录也查过来
*/
public static String getRowKey(String parKey,String call1,String bulidTime,String call2,String flag,String duration){
return parKey+"_"+
call1+"_"+
bulidTime+"_"+
call2+"_"+
flag+"_"+
duration;
}