云数据库HBase的Rowkey设计在数据分区和数据查询中很重要,本节介绍设计Rowkey前需要考虑的一些问题以及设计示例。
问题考虑
- 问题一:Rowkey是唯一的吗?
相同的Rowkey在HBase中认为是同一条数据的多个版本,查询时默认返回最新版本的数据,所以通常Rowkey都需要保证唯一,除非用到多版本特性。
最佳设计示例:Rowkey相当于数据库的主键。Rowkey表示一条记录。Rowkey可以是一个字段也可以是多个字段接起来。Rowkey为[userid]表示每个用户只有一条记录, Rowkey为[userid][orderid]表示每个用户有多条记录。
- 问题二:满足哪种查询场景?
Rowkey的设计限制了数据的查询方式,HBase有两种查询方式。
- 根据完整的Rowkey查询(get方式),例如
SELECT * FROM table WHERE Rowkey = ‘abcde’
。说明 get方式需要知道完整的Rowkey,即组成Rowkey所有字段的值都是确定的。 - 根据Rowkey的范围查询(scan方式),例如
SELECT * FROM table WHERE ‘abc’ < Rowkey <’abcx’
。说明 scan方式需要知道Rowkey左边的值,例如您使用英文字典查询pre开头的所有单词,也可以查询prefi开头的所有单词,不能查询中间或结尾为prefi的单词。
最佳设计示例:在有限的查询方式下如何实现复杂查询?以下方法可以帮您实现。- 再新建一张表作为索引表。
- 使用Filter在服务端过滤不需要的数据。
- 使用二级索引。
- 使用反向scan方法实现倒序(将新数据排在前面),
scan.setReverse(true)
。说明 反向scan的性能比正常scan性能差,如果大部分是倒序场景可以体现在Rowkey设计上,例如[hostname][log-event][timestamp] => [hostname][log-event][Long.MAX_VALUE - timestamp]
。
- 根据完整的Rowkey查询(get方式),例如
- 问题三:数据足够分散,会存在堆积的热点现象吗?
散列的目的是将数据分散到不同的分区,不至于产生热点使某一台服务器终止,其他服务器空闲,充分发挥分布式和并发的优势。
最佳设计示例:- 设计md5散列算法:
[userId][orderid] => [md5(userid).subStr(0,4)][userId][orderid]
。 - 设计反转:
[userId][orderid] => [reverse(userid)][orderid]
。 - 设计取模:
[timestamp][hostname][log-event] => [bucket][timestamp][hostname][log-event]; long bucket = timestamp % numBuckets
。 - 增加随机数:
[userId][orderid] => [userId][orderid][random(100)]
。
- 设计md5散列算法:
- 问题四:Rowkey可以再短点吗?
短的Rowkey可以减少数据量,提高数据查询和数据写入效率。
最佳设计示例:- 使用Long或Int代替String,例如
'2015122410' => Long(2015122410)
。 - 使用编码代替名称,例如
'淘宝' => tb
。
- 使用Long或Int代替String,例如
- 问题五:使用scan方式会查询出不需要的数据吗?
会的。场景举例:table1的Rowkey为
column1+ column2+ column3
,如果您需要查询column1= host1
的所有数据,使用scan 'table1',{startkey=> 'host1',endkey=> 'host2'}
语句。如果有一条记录为column1=host12
,那么此记录也会查询出来。最佳设计示例:- 设计字段定长,
[column1][column2] => [rpad(column1,'x',20)][column2]
。 - 添加分隔符,
[column1][column2] => [column1][_][column2]
。
- 设计字段定长,
常见设计示例
- 日志类、时间序列数据。列举出以下三个场景设计Rowkey。
- 查询某台机器某个指标某段时间内的数据,Rowkey设计为
[hostname][log-event][timestamp]
。 - 查询某台机器某个指标最新的几条数据,Rowkey设计为
timestamp = Long.MAX_VALUE - timestamp; [hostname][log-event][timestamp]
。 - 查询的数据存在只有时间一个维度或某一个维度数据量巨大的情况,Rowkey设计为
long bucket = timestamp % numBuckets; [bucket][timestamp][hostname][log-event]
。
- 查询某台机器某个指标某段时间内的数据,Rowkey设计为
- 交易类数据。列举出以下四个场景设计Rowkey。
- 查询某个卖家某段时间内的交易记录,Rowkey设计为
[seller id][timestamp][order number]
。 - 查询某个买家某段时间内的交易记录,Rowkey设计为
[buyer id][timestamp][order number]
。 - 根据订单号查询,Rowkey设计为
[order number]
。 - 查询中同时满足三张表,一张买家维度表Rowkey设计为
[buyer id][timestamp][order number]
。一张卖家维度表Rowkey设计为[seller id][timestamp][order number]
。一张订单索引表Rowkey设计为[order number]
。
- 查询某个卖家某段时间内的交易记录,Rowkey设计为