RowKey 设计
RowKey 概念
HBase 中 RowKey 可以唯一标识一行记录, 在 HBase 查询的时候有以下几种方式:
-
通过 Get 方式, 指定 RowKey 获取唯一一行记录
-
通过 Scan 方式, 设置 startRow 和 stopRow 参数进行范围匹配
-
全表扫描, 直接扫描表中所有行记录
从字面意思来看, RowKey 就是行健的意思, 在增删改查的过程中充当了主键的作用, 它可以是任意字符串, 在 HBase 内部 RowKey 保存为字节数组.
HBase 中的数据是按照 RowKey 的 ASCII 字典顺序进行全局排列的, ASCII 字典顺序举一个例子:
假如有 5 个 Rowkey:"012", "0", "123", "234", "3",按 ASCII 字典排序后的结果为:"0", "012","123", "234", "3"
因此我们设计 RowKey 时,需要充分利用排序存储这个特性,将经常一起读取的行存储放到一起,要避免做全表扫描,因为效率特别低。
多条件查询
假设一个场景. 用户每天产生的消息用如下 RowKey 表示: userid-data-messageid. 我们查询一个用户所有天的消息记录可以匹配 userid-, 但是当我们需要查询一天所有用户发的消息记录的话就需要匹配 -data-, 这样 B+ Tree 就无法索引, 从而只能全表扫描.
为了解决以上问题, 我们回想一下 MySQL 非主键索引的查询方式, 每一个非主键索引都维护着一个 B+ Tree, 叶子节点上存放的是索引值和主键值, 然后通过主键值进行二次查找主键索引的 B+ Tree 找到一行的值.
所以我们也可以借鉴这种方法, 为每一个索引维护一个索引表. 比如匹配 -data-, 就将索引表的 RowKey 存为 data-userid-messageid, 这一行的值为 "data, userid, messageid, 原表的RowKey". 这样我们就可以使用索引表的 RowKey 匹配到符合 -data- 匹配条件的 userid-data-messageid(原表的RowKey), 再根据这些原表的 RowKey Get 查找所有的行记录.
数据热点
糟糕的 RowKey 设计是热点的源头, 会使得大量 Client 访问集群中的一个或者几个节点, 这样会使得热点机器服务几乎不可用.
所以我们应该优化 RowKey 的设计, 使数据被写入到集群的多个节点, 而不是一个.
在实际使用中, 主要有两个方法来避免热点问题: 反转 RowKey, 加前缀.
反转 RowKey
反转 RowKey 这个字节数组.
以手机号为例子, 手机号前缀的变化少 (158, 159 等), 如果正常存储极极有可能被存放在一个节点上. 手机号后半部分变化很大, 所以我们采用反转的方式让其均匀分布.
加前缀
将原本写好的 RowKey 计算哈希值, 然后将运算后的哈希值作为前缀用来 "打散" 数据.
RowKey 长度
我们在检索的时候, RowKey 是要作为 B+ Tree 节点值来索引的. 如果 RowKey 过长, 那么内存中存放的索引就越少, 影响效率. 另外, 我们目前使用的服务器都是 64 位的, 内存是按照 8Byte 对齐的, 因此设计 RowKey 是一般做成 8Byte 的整数倍, 如 16Byte 或者 24 Byte, 可以提高寻址效率.
标签:userid,索引,RowKey,设计,HBase,data,主键 From: https://www.cnblogs.com/geraldkohn/p/17091091.html