解密HBase RowKey设计之原则与最佳实践

HBase是一种分布式、可扩展、支持海量数据存储的NoSQL数据库,面向列式存储,其底层是基于HDFS实现,集群通过Zookeeper管理,可以进行数据快速访问。

HBase中每一个Region维护着StartRowKey与EndRowKey,如果加入的数据符合某个Region维护的RowKey范围,则该数据交给这个Region维护。那么依照这个原则,我们可以将数据所要投放的分区提前大致的规划好,以提高HBase性能。

HBase中一条数据的唯一标识就是RowKey,那么这条数据存储于哪个分区,取决于RowKey处于哪个一个预分区的区间内,设计RowKey的主要目的,就是让数据均匀的分布于所有的Region中,在一定程度上防止数据倾斜。接下来我们就谈一谈RowKey的设计原则和常用的设计方案。

一、设计原则

HBase中的行是按照Rowkey的字典顺序排序的,这种设计优化了Scan操作,可以将相关的行以及会被一起读取的行存取在临近位置,便于Scan,然而糟糕的RowKey设计是数据热点的源头。【数据热点发生在大量的Client直接访问集群的一个或极少数个节点(可能是读,写或者其他操作)】。大量访问会使热点Region所在的单个机器超出自身承受能力,引起性能下降甚至Region不可用,这也会影响同一个RegionServer上的其他Region,导致主机无法服务其他Region的请求。以下是几个RoeKey的设计原则:

1. 长度原则

在HBase中,要访问一个Cell(单元格),需要有RowKey、列蔟、列名,如果RowKey、列名太大,就会占用较大内存空间,所以RowKey和列的长度应该尽量短小。RowKey的最大长度是64KB,建议越短越好,10-100长度即可,最好是8的整数倍。

另:如果RowKey是数字类型的,建议使用Long类型,因为Long类型为8个字节,8个字节可以保存非常大的无符号整数,例如:18446744073709551615。如果是字符串,是按照一个字节一个字符方式保存,需要快3倍的字节数存储。

2. 散列原则

如果RowKey按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将RowKey的高位作为散列字段,由程序随机生成,低位放时间字段,这样将提高数据均衡分布在每个RegionServer,以实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息,所有的数据都会集中在一个RegionServer上,这样在数据检索的时候负载会集中在个别的RegionServer上,造成热点问题,会降低查询效率。

3. 唯一原则

在设计RowKey时,必须保证RowKey的唯一性,由于在HBase中数据存储是Key-Value形式,若向HBase中同一张表插入相同RowKey的数据,则原先存在的数据会被新的数据覆盖。而且rowkey是按照字典顺序排序存储的,因此,设计rowkey的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。

4. 排序原则
HBase会把RowKey按照ASCII进行自然有序排序,所以反过来我们在设计RowKey的时候可以根据这个特点来设计完美的RowKey,好好的利用这个特性就是排序原则。

二、常用设计方案

1. 反转Key

将固定宽度的行键或数字行键颠倒过来,使更改最频繁的部分(最低有效位)位于最前面,反转分为一般数据反转和时间戳反转,其中以时间戳反转较常见。

适用场景:

比如咱们初步设计出的RowKey在数据分布上不均匀,但RowKey尾部的数据却呈现出了良好的随机性(注意:随机性强代表经常改变,没意义,但分布较好),此时,可以考虑将RowKey的信息翻转,或者直接将尾部的bytes提前到RowKey的开头。反转可以有效的使RowKey随机分布,但是反转后有序性肯定就得不到保障了,因此它牺牲了RowKey的有序性。

缺点:

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

2. Slat

Slat是将每一个RowKey加一个前缀,前缀使用一些随机字符,使得数据分散在多个不同的Region,达到Region负载均衡的目标。由于此分配是随机的,如果希望按字典顺序检索行,则需要做更多的工作,通过这种方式,Slat增加了写时的吞吐量,但在读时要付出代价。

适用场景:

比如咱们设计的RowKey是有意义的,但是数据类似,随机性比较低,反转也没法保证随机性,这样就没法根据RowKey分配到不同的Region里,这时候就可以使用加盐的方式了。

需要注意随机数要能保障数据在所有Regions间的负载均衡,也就是说分配的随机前缀的种类数量应该和你想把数据分散到的那些region的数量一致。只有这样,加盐之后的rowkey才会根据随机生成的前缀分散到各个region中,避免了热点现象。

缺点:

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

3. Hash散列

用Hash散列来替代随机Salt前缀的好处是让一个给定的行有相同的前缀,这在分散了Region负载的同时,使读操作也能够缩短,确定性Hash(比如MD5后取前4位左前缀)能让客户端重建完整的Rowkey可以直接使用get操作,获取想要的行。数据量越大这样的会使分区更加均衡,如果Rowkey是数字类型的,也可以考虑Mod方法。

适用场景:

其实哈希和加盐的适用场景类似,但是由于加盐方法的前缀是随机数,用原rowkey查询时不方便,因此出现了哈希方法,由于哈希是使用各种常见的算法来计算出的前缀,因此哈希既可以使负载分散到整个集群,又可以轻松读取数据。

缺点:

与反转类似,哈希也打乱了RowKey的自然顺序,因此也不利于Scan。

三、总结

本文讲解了HBase的数据热点问题,主要是由于RowKey的设计不合理导致,而基本设计原则包括RowKey的长度,Hash,唯一性和排序,常见的几种设计方案有Slat(拼接),Hash散列,Key反转。

对于这几种RowKey的设计方案,单一的设计有时候并不能有效的解决数据热点问题,需要结合实际情况,多种方案综合使用,所以各位程序员遇到问题之后,需要多多测试,找到合适自己问题的解决方案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值