[toc]

1. RowKey的作用

1.1 介绍

Rowkey是每一行的主键,在每行的开头, 也是可以存储数据的,只是它具有索引的作用,一般不是存在业务数据,而是发挥索引作用,所以里面填充什么值很重要,此为Rowkey设计

1.2 RowKey在查询中的作用

HBase中RowKey可以唯一标识一行记录,在HBase中检索数据有以下三种方式:

  • 通过 get 方式,指定 RowKey 获取唯一一条记录
  • 通过 scan 方式,设置 startRow 和 stopRow 参数进行范围匹配
  • 全表扫描,即直接扫描整张表中所有行记录

链接:https://www.jianshu.com/p/89bcd80890d6

当大量请求访问HBase集群的一个或少数几个节点,造成少数RegionServer的读写请求过多、负载过大,而其他RegionServer负载却很小,这样就造成热点现象。大量访问会使热点Region所在的主机负载过大,引起性能下降,甚至导致Region不可用。所以我们在向HBase中插入数据的时候,应尽量均衡地把记录分散到不同的Region里去,平衡每个Region的压力。

下面根据一个例子分别介绍下根据RowKey进行查询的时候支持的情况。 如果我们RowKey设计为uid+phone+name,那么这种设计可以很好的支持一下的场景:

uid=873969725 AND phone=18900000000 AND name=zhangsan
uid= 873969725 AND phone=18900000000
uid= 873969725 AND phone=189?
uid= 873969725

难以支持的场景:

phone=18900000000 AND name = zhangsan
phone=18900000000 
name=zhangsan

从上面的例子中可以看出,在进行查询的时候,根据RowKey从前向后匹配,所以我们在设计RowKey的时候选择好字段之后,还应该结合我们的实际的高频的查询场景来组合选择的字段,越高频的查询字段排列越靠左。

1.3 RowKey在Region中的作用

在 HBase 中,Region 相当于一个数据的分片,每个 Region 都有StartRowKey和StopRowKey,这是表示 Region 存储的 RowKey 的范围,HBase 表的数据时按照 RowKey 来分散到不同的 Region,要想将数据记录均衡的分散到不同的Region中去,因此需要 RowKey 满足这种散列的特点。此外,在数据读写过程中也是与RowKey 密切相关,RowKey在读写过程中的作用:

  • 读写数据时通过 RowKey 找到对应的 Region;
  • MemStore 中的数据是按照 RowKey 的字典序排序;
  • HFile 中的数据是按照 RowKey 的字典序排序。

2. RowKey设计原则

长度原则
RowKey是一个二进制码流,可以是任意字符串,最大长度为64kb,实际应用中一般为10-100byte,以byte[]形式保存,一般设计成定长。建议越短越好,不要超过16个字节,原因如下:

数据的持久化文件HFile中时按照Key-Value存储的,如果RowKey过长,例如超过100byte,那么1000w行的记录,仅RowKey就需占用近1GB的空间。这样会极大影响HFile的存储效率。 MemStore会缓存部分数据到内存中,若RowKey字段过长,内存的有效利用率就会降低,就不能缓存更多的数据,从而降低检索效率。 目前操作系统都是64位系统,内存8字节对齐,控制在16字节,8字节的整数倍利用了操作系统的最佳特性。

唯一原则
必须在设计上保证RowKey的唯一性。由于在HBase中数据存储是Key-Value形式,若向HBase中同一张表插入相同RowKey的数据,则原先存在的数据会被新的数据覆盖。

排序原则
HBase的RowKey是按照ASCII有序排序的,因此我们在设计RowKey的时候要充分利用这点。

散列原则
设计的RowKey应均匀的分布在各个HBase节点上。

3. RowKey字段选择

RowKey字段的选择,遵循的最基本原则是唯一性,RowKey必须能够唯一的识别一行数据。无论应用的负载特点是什么样,RowKey字段都应该参考最高频的查询场景。数据库通常都是以如何高效的读取和消费数据为目的,而不是数据存储本身。然后,结合具体的负载特点,再对选取的RowKey字段值进行改造,组合字段场景下需要重点考虑字段的顺序。

4. 避免数据热点的方法

在对HBase的读写过程中,如何避免热点现象呢?主要有以下几种方法:

Reversing
如果经初步设计出的RowKey在数据分布上不均匀,但RowKey尾部的数据却呈现出了良好的随机性,此时,可以考虑将RowKey的信息翻转,或者直接将尾部的bytes提前到RowKey的开头。Reversing可以有效的使RowKey随机分布,但是牺牲了RowKey的有序性。

缺点:
利于Get操作,但不利于Scan操作,因为数据在原RowKey上的自然顺序已经被打乱。

Salting
Salting(加盐)的原理是在原RowKey的前面添加固定长度的随机数,也就是给RowKey分配一个随机前缀使它和之间的RowKey的开头不同。随机数能保障数据在所有Regions间的负载均衡。

缺点:
因为添加的是随机数,基于原RowKey查询时无法知道随机数是什么,那样在查询的时候就需要去各个可能的Regions中查找,Salting对于读取是利空的。并且加盐这种方式增加了读写时的吞吐量。

Hashing
基于 RowKey 的完整或部分数据进行 Hash,而后将Hashing后的值完整替换或部分替换原RowKey的前缀部分。这里说的 hash 包含 MD5、sha1、sha256 或 sha512 等算法。

缺点:
与 Reversing 类似,Hashing 也不利于 Scan,因为打乱了原RowKey的自然顺序。

时间戳反转
一个常见的数据处理问题是快速获取数据的最新版本,使用反转的时间戳作为RowKey的一部分对这个问题十分有用,可以用Long.Max_Value - timestamp追加到key的末尾。 举例:
在推贴流表里,你使用倒序时间戳(Long.MAX_VALUE - 时间戳)然后附加上用户ID来构成行健。现在你基于用户ID扫描紧邻的n行就可以找到用户需要的n条最新推帖。这里行健的结构对于读性能很重要。把用户ID放在开头有助于你设置扫描,可以轻松定义起始键。

https://www.cnblogs.com/swordfall/p/10597802.html

5. 总结

在HBase的使用过程,设计RowKey是一个很重要的一个环节。我们在进行RowKey设计的时候可参照如下步骤:

结合业务场景特点,选择合适的字段来做为RowKey,并且按照查询频次来放置字段顺序 通过设计的RowKey能尽可能的将数据打散到整个集群中,均衡负载,避免热点问题 设计的RowKey应尽量简短

链接:https://www.jianshu.com/p/89bcd80890d6 https://www.cnblogs.com/duanxz/p/4660784.html