目录
HBase系列:
前言
上一篇中我们提到了HBase的读写原理,可以看出HBase是为写操作优化,更适合写多读少的场景,尤其是因为数据按列族和Region切分成一个个的StoreFile,在跨多文件查询数据的时候就会很慢。同时,由于Region切分策略,会让HFile出现数据倾斜的情况,因此我们在实际应用中首先要先设置预分区,指定HBase表有几个分区,每个分区内的RowKey范围,然后我们只要将RowKey的值尽可能均匀的放置在这些Region内即可。本篇我们就来介绍如何通过RowKey的设计提升HBase的读性能。
前面的文章中也提到,HBase只能通过RowKey查询数据:指定RowKey查询、指定RowKey区间查询、全表扫描。所以通常我们也会利用第三方组件如solr,elasticsearch对HBase做二级索引,提升查询效率,在后面的文章中再具体介绍。
RowKey设计
设计原则
Rowkey设计的优劣直接影响读写性能,HBase中的数据是按照RowKey的ASCII 字典顺序进行全局排序。ASCII码表:
RowKey设计应遵循以下原则:
长度原则
RowKey是一个二进制存储的值,RowKey的长度尽量控制在10~100个字节,建议是越短越好。 原因如下:
- HFile 按照KeyValue存储,如果RowKey过长比如500个字节,1000万列数据光是RowKey就要占用500*1000万=50亿个字节≈5GB数据,非常影响HFile的存储效率;
- MemStore中维护着Flush之前的数据,如果RowKey字段过长的话会占用很多内存,导致系统无法缓存更多的数据,影响查询效率;
唯一原则
由于RowKey用来唯一标识一行记录,所以必须在设计上保证RowKey的唯一性:
- HBase中数据存储是Key-Value形式,若HBase中同一表插入相同Rowkey,则原先的数据会被覆盖掉(如果表的version设置为1的话),所以务必保证Rowkey的唯一性;
排序原则
HBase会把RowKey按照ASCII进行自然有序排序,所以反过来我们在设计RowKey的时候可以根据这个特点来设计完美的RowKey,好好的利用这个特性就是排序原则;
散列原则
在上面也提到,只要我们尽量将数据均衡的分布在每个Region内,就可以预防数据倾斜的情况。假如按照时间戳作为rowkey的前缀会导致大量数据堆积在一个RegionServer上导致Region热点问题,当大量读写请求到该RegionServer上时会对该RS的负载压力过高从而影响性能甚至出现故障;
解决热点问题
解决RegionServer热点现象需要良好的RowKey设计,让数据尽可能均匀的分布在每个Region下,通常有三种方案:加盐、反转、散列。
Salt加盐
在原RowKey的前面添加固定长度的随机数,也就是给RowKey分配一个随机前缀使它和之前的RowKey的开头不同。
例:在一个有3个Region以(,h)、[h,x)、[x,z)为Region分区的HBase表中,有下面三个rowkey:wykcsdn001,wykcsdn002,wykcsdn003 ,这三个rowkey会被分布在[x,z)这个region内,加盐后变成qwe_wykcsdn001,asd_wykcsdn002,zxc_wykcsdn003,这三个rowkey会被均匀分布在三个region分区内。
wykcsdn001-->qwe_wykcsdn001
wykcsdn002-->asd_wykcsdn002
wykcsdn003 -->zxc_wykcsdn003
加盐之后的吞吐量是之前的三倍,但加盐也有缺点:盐是随机字符串,在查找的时候不知道该盐的内容,读这些数据时需要耗费更多的时间,所以加盐增加了写操作的吞吐量,不过缺点是同时增加了读操作的开销。
Reverse反转
针对固定长度的Rowkey进行反转,将Rowkey中经常改变的部分放在最前面,可以有效的随机Rowkey。典型的比如手机号,时间戳这类数据前缀几乎都是一样的,最后几位更有随机性。反转之后得到的字符串即保证了随机性又不会像加盐一样无法得知rowkey的真实值。但反转也牺牲了Rowkey的有序性。
例:
182xxxx7890-->0987xxx281
182xxxx6379-->9736xxx281
182xxxx1355-->5531xxx281
20200911145043-->34054111900202
20200911145058-->85054111900202
20200911145501-->10554111900202
Hash散列或Mod取余
hash比较好理解,将原来的rowkey内容或部分前缀通过hash算法(MD5、sha1、sha256、sha512)生成更加随机的字符串。相比于加盐的方式,hash后的字符串既可以使负载分散到整个集群,又可以通过原rowkey的值算出hash值来读取数据。
对于纯数字型的rowkey,也可以使用mod取余的方式来将其打散。
例:
wyk001-->66079de6861d926bcd08da5878283601
wyk002-->344fd201bd135f5ad7d45ad5668e1438
wyk003-->81264b3ace502fec8c76a6991c0eeaed
123456789%21-->15
123459999%21-->12
123458888%21-->14
在工作中,我们也可以结合项目的实际情况结合这几种方式来设计RowKey,以预防Region热点。
希望本文对你有帮助,请点个赞鼓励一下作者吧~ 谢谢!