HBase Rowkey设计指南、rowkey设计案例剖析、什么是热点问题 15
前言
如何评判一张HBase表设计的好不好,重点看它的rowkey设计的好不好,所以HBase的rowkey设计是非常重要的。但是rowkey到底是什么?特点如下:
- 类似于mysql、oracle中的主键,用于标示唯一的行;
- 完全是由用户指定的一串不重复、唯一的字符串;
- hbase中的数据永远是根据rowkey的字典顺序来排序的
1. HBase中Rowkey的作用
- 读写数据时通过rowkey找到对应的Region;
- MemStore中的数据按Rowkey字典顺序排序;
- HFile中的数据按Rowkey字典顺序排序。
2. HBase中Rowkey对查询的影响
如果我们的rowkey设计为uid+phone+name,那么这种设计可以很好的支持以下的场景:
- uid = 111 AND phone = 123 AND name = iteblog
- uid = 111 AND phone = 123
- uid = 111 AND phone = 12?
- uid = 111
但是难以支持如下场景
- phone = 123 AND name = iteblog
- phone = 123
- name = iteblog
3. HBase中Rowkey对Region划分的影响
hbase表的数据是按照rowkey来分散到不同region,不合理的rowkey设计会导致热点问题。
什么是热点问题?
热点问题是大量的client直接访问集群的一个或极少数个节点,而集群中的其他节点却处于相对空闲状态。
如上图,Region1上的数据是Region2的5倍,这样会导致Region1的访问频率比较高,进而影响这个Region所在机器的其他region。
4. Rowkey的设计技巧
4.1 避免热点的方法 - Salting(加盐)
这里的加盐不是秘密学中的加盐,而是rowkey的前面增加随机数。具体就是给rowkey分配一个随机前缀,以使得它和之前排序不同。分配的前缀种类数量应该和你想使数据分散到不同的region的数量一致。
如果你有一些热点 rowkey反复出现在其他分部均匀的rowkey中,加盐是很有用的。
假如你有下列rowkey,你表中每一个region对应字母表中每一个字母。以‘a’开头是同一个region,以‘b’开头是同一个region。在表中,所有以‘f’开头的都在同一个region,它们的rowkey像下面这样:
foo0001
foo0002
foo0003
foo0004
现在,鸡舍要将上面的这个region里面的数据,分散到4个region中。可以用4个不同的盐:‘a’,‘b’,‘c’,‘d’,在这个方案下,每一个字母前缀都会在不同的region中。加盐之后,你有了下面的rowkey:
a-foo0003
b-foo0001
c-foo0004
d-foo0002
加盐这种方法增加了写时的吞吐量,但是读时有了额外代价
4.2 避免热点的方法 - Hashing
Hashing的原理是计算rowkey的hash值,然后取hash的部分字符串和原来的rowkey进行拼接。这里说的hash包含MD5、sha1、sha256或sha512等算法。比如我们有如下的rowkey:
foo0001
foo0002
foo0003
foo0004
我们使用md5计算这些rowkey的hash值,然后取前6位和原来的rowkey拼接得到新的rowkey:
95f18cfoo0001
6ccc20foo0002
b61d00foo0003
1a7475foo0004
4.3 避免热点的方法 - Reversing
reversing的原理是反转一段固定长度或者全部的键。比如我们有一些url,并作为rowkey:
flink.iteblog.com
www.iteblog.com
carbondata.iteblog.com
def.iteblog.com
这些url其实属于同一个域名,但是由于前面不一样,导致数据不在一起存放。我们可以对其进行反转,如下:
moc.golbeti.knilf
moc.golbeti.www
moc.golbeti.atadnobrac
moc.golbeti.fed
经过这个之后,这些url的数据就可以放一起了。
5. rowkey 设计案例剖析
5.1 交易类表Rowkey设计
- 查询某个卖家某段时间内的交易记录
sellerId + timestamp + orderId - 查询某个买家某段时间内的交易记录
buyerId + timestamp + orderId - 根据订单号查询
orderNo - 如果某个商家卖了很多商品,可以如下设计rowkey实现快速搜索
salt + sellerId + timestamp 其中,salt是随机数。
可以支持的场景:
* 全表 scan
* 按照 sellerId 查询
* 按照 sellerId + timestamp查询
5.1 金融风控 rowkey 设计
查询某个用户的用户画像数据
- prefix + uid
- prefix + idcard
-
prefix + tele
其中 prefix = substr(md(uid),0,x),x取5-6。uid、idcard以及tele分别表示用户唯一标识符、身份证、手机号码。
5.2 联网 Rowkey 设计
- 查询某辆车在某个时间范围的交易记录
carId + timestamp - 某批次的车太多,造成热点
prefix + carId + timestamp 其中 prefix = substr(md5(uid),0 ,x)
5.3 查询最近的数据
查询用户最新的操作记录或者查询用户某段时间的操作记录,RowKey 设计如下:
uid + Long.Max_Value - timestamp
支持的场景
- 查询用户最新的操作记录
Scan [uid] startRow [uid][000000000000] stopRow [uid][Long.Max_Value - timestamp] - 查询用户某段时间的操作记录
Scan [uid] startRow [uid][Long.Max_Value – startTime] stopRow [uid][Long.Max_Value - endTime]