1 、预分区
1)预分区概述
HBase表在刚刚创建时,只有一个分区(region),当一个Region过大时(>10G)时,将会被RegionServer进行Split分裂成两个分区。表在进行Split时,会耗费大量的资源,频繁的分区对HBase的性能有着巨大的影响。
每一个region维护着startRow与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护。那么依照这个原则,我们可以将数据所要投放的分区提前大致的规划好,就可以提高HBase性能。
HBase提供了预分区功能,即用户可以创建表的时候对表按照一定的规则分区。
2)设置预分区
1.手动设定预分区
(1)生成给定数组内数值范围的预分区
hbase(main):038:0> create 'table1','info',SPLITS => ['100','200','300','400']
(2)生成16进制序列预分区
hbase(main):038:0> create 'table2','info',{NUMREGIONS => 10, SPLITALGO => 'HexStringSplit'}
(3)按照文件中设置的规则预分区
创建splits.txt文件内容如下:
[user@hadoop001 hbase]$ vim splits.txt
aaaa
bbbb
cccc
dddd
然后执行:
hbase(main):038:0> create 'table3','info',SPLITS_FILE => 'splits.txt'
(4)使用JavaAPI创建预分区
// 自定义算法,产生一系列Hash散列值存储在二维数组中
byte[ ] [ ] splitKeys = 某个散列值函数
// 创建HbaseAdmin实例
HBaseAdmin hAdmin = new HBaseAdmin(HbaseConfiguration.create());
// 创建HTableDescriptor实例
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
// 通过HTableDescriptor实例和散列值二维数组创建带有预分区的Hbase表
hAdmin.createTable(tableDesc, splitKeys);
2 、RowKey设计
1)概念描述
一条数据的唯一标识就是rowkey,那么这条数据存储于哪个分区,取决于rowkey处于哪一个预分区的区间内,设计rowkey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。接下来我们就谈一谈rowkey常用的设计方案。
2)RowKey设计方案
RowKey除了根据业务和查询需求设计之外,还要注意以下三点:
1. 生成随机数、hash、散列值
HBase中的行是按照RowKey的字典顺序排序的。这对Scan操作非常友好,因为RowKey相近的行总是存储再相近的位置,顺序读的效率要远高于随机读。但是如果大量的读写操作总是集中在某个RowKey范围,那么又会造成Region热点,拖累RegionServer的性能,因此,要适当的将Rowkey打散。
比如:
原本rowKey为101的,SHA1后变成:dbc0f004854457f59fb16ab863a3a1722cef553f
原本rowKey为301的,SHA1后变成:787d41d9c35c57ef9e4aba799bacefac312149a4
原本rowKey为501的,SHA1后变成:2c9a62c3748f484690d547c0d707aededf04fbd2
在做此操作之前,一般我们会选择从数据集中抽取样本,来决定什么样的rowKey来Hash后作为每个分区的临界值。
2. 反转固定格式的数值
以手机号为例,手机号的前缀变化较少,如138、135等,但是后半部分变化很多。如果将它反转过来,就可以有效的避免热点数据的读写操作。反转时间并不算是严格意义的数据”打散”,但是可以调整数据的时间顺序。如果将时间按照字典序排列,最近产生的数据会排在旧数据后面。可以使用一个大值(99999999减去yyyyMMdd),这样新的数据就排在前面了。
13873339063 转成 36093337831
13573339154 转成 45193337531
99999999 – 20211111 = 79788888
99999999 – 20211212 = 79788787
3. 加盐(salting)+ 哈希(hashing)
这里的”加盐”与密码学中的”加盐”不是一回事。这里的意思是指在RowKey的前面增加一些前缀。加盐的前缀种类越多,RowKey就被打得越散。前缀不可以是随机的,因为必须让客户端能够完整的重构RowKey。我们一般会拿原来的RowKey或者其中一部分计算hash值,然后再对hash值作为前缀。
asd8_20211224000001
67th_20211224000002