HBase的Rowkey设计总结

文章目录

    • HBase的Rowkey设计总结
      • 一、引言
      • 二、Rowkey设计原则
          • 1、Rowkey的唯一原则
          • 2、Rowkey的排序规则
          • 3、Rowkey的散列原则
          • 4、Rowkey的长度原则

HBase的Rowkey设计总结

一、引言

HBase属于Nosql数据库,由于其存储和读写的高性能,在OLAP即时分析中发挥重要的作用。

HBase的查询只能通过其Rowkey来查询(因为Rowkey用来标识唯一一行记录),所以说Rowkey的设计优劣直接影响整个读写性能。

HBase中的数据是按照Rowkey的ASCII字典顺序进行全局排序的。

Rowkey排序时会先比较两个Rowkey的第一个字节,如果相同,然后会比较第二个字符,依次类推,直到第X个字符时,已经超出了其中一个Rowkey的长度,短的则排在前面。

由于HBase是通过Rowkey查询的,一般Rowkey上都会存一些比较关键的检索信息,所以我们要根据具体需求以及查询方式来进行数据存储格式的设计,避免全表扫描,效率极低。

二、Rowkey设计原则

1、Rowkey的唯一原则

必须在设计上保证其唯一性,由于HBase中存储的是K-V形式,如果同一表中插入了相同的Rowkey,则原来的数据会被覆盖掉(假设version为1),所以必须要保证Rowkey的唯一性。

2、Rowkey的排序规则

HBase的Rowkey是默认按照字典由小到大排序的,所以在设计时可以充分利用这点。比如当遇到这种情景:视频网站上对影片《复联4》的弹幕消息是按照时间倒序排序的,这时Rowkey就要设计成和时间顺序相关,而实现倒序,则可以使用Long.MAX_VALUE - 弹幕发表时间的 lang 值作为Rowkey的前缀。

3、Rowkey的散列原则

我们设计的Rowkey应均匀的分布在各个HBase节点上。拿常见的时间戳举例,假如Rowkey是按系统时间戳的方式递增,Rowkey的第一部分如果是时间戳信息的话将造成所有新数据都在一个RegionServer上堆积的热点现象,也就是通常说的Region热点问题, 热点发生在大量的client直接访问集中在个别RegionServer上(访问可能是读,写或者其他操作),导致单个RegionServer机器自身负载过高,引起性能下降甚至Region不可用,常见的是发生jvm full gc或者显示region too busy异常情况,当然这也会影响同一个RegionServer上的其他Region。

通常有3种办法来解决这个Region热点问题:

  • Reverse反转

    针对固定长的的Rowkey进行反转后存储,这样可以让Rowkey中经常变动的那一部分放在最前面,可以有效地散列Rowkey

    比如手机号的情景:可以将手机号反转后的字符串作为Rowkey,这样就可以避免大量固定开头(135x、137x …等)导致热点问题。

    但是这样做的缺点就是牺牲了Rowkey的有序性。

  • Salt加盐

    Salting 是将每一个Rowkey加一个前缀,可以使用随机字符,使得数据分散到多个不同的Region,让Region负载均衡。

    比如在一个有4个Region(注:以 [ ,a)、[a,b)、[b,c)、[c, )为Region起至)的HBase表中

    加Salt前的Rowkey:abc001、abc002、abc003

    我们分别加上a、b、c前缀,加Salt后Rowkey为:a-abc001、b-abc002、c-abc003

    可以看到,加盐前的Rowkey默认会在第2个region中,加盐后的Rowkey数据会分布在3个region中,理论上处理后的吞吐量应是之前的3倍。

    不过缺点是:由于前缀是随机的,读这些数据时需要耗费更多的时间,所以Salt增加了写操作的吞吐量,同时增加了读操作的开销。

  • Hash散列或者Mod

    用Hash散列来代替随机Salt前缀的好处是能让上一个给定的行有相同的前缀,这使得分散Region负载的同时,使读操作也能够推断。确定性Hash(比如MD5后取前4位做前缀)能让客户端重建完整的Rowkey,可以get直接想要的。

    例如将上述的原始Rowkey经过hash处理,此处我们采用md5散列算法取前4位做前缀,结果如下

    9bf0-abc001 (abc001在md5后是9bf049097142c168c38a94c626eddf3d,取前4位是9bf0)

    7006-abc002

    95e6-abc003

    若以前4个字符作为不同分区的起止,上面几个Rowkey数据会分布在3个region中。实际应用场景是当数据量越来越大的时候,这种设计会使得分区之间更加均衡。

    如果Rowkey是数字类型的,也可以考虑Mod方法,即直接对Region个数取模,使用取模后的结果来进行散列。

4、Rowkey的长度原则

Rowkey是一个二进制,Rowkey的长度被很多开发者建议说设计在10~100个字节,建议是越短越好。

原因有两点:

​ 其一是HBase的持久化文件HFile是按照KeyValue存储的,如果Rowkey过长比如500个字节,1000万列数据光Rowkey就要占用500*1000万=50亿个字节,将近1G数据,这会极大影响HFile的存储效率。
​ 其二是MemStore缓存部分数据到内存,如果Rowkey字段过长内存的有效利用率会降低,系统无法缓存更多的数据,这会降低检索效率。

需要指出的是不仅Rowkey的长度是越短越好,而且列族名、列名等尽量使用短名字,因为HBase属于列式数据库,这些名字都是会写入到HBase的持久化文件HFile中去,过长的Rowkey、列族、列名都会导致整体的存储量成倍增加。

你可能感兴趣的:(HBase)