hbase预分区
2024-10-09 18:01:54 # hbase # 常用细节

hbase预分区

hbase split遇到的两个问题

首先在说明这两个问题之前需要介绍一下hbase的split机制是什么

hbase的split机制

hbase的region切分和合并是为了保持hbase有良好的扩张性

当一个Region大到一定程度,会进行分裂(split)

hbase默认的split机制是min(r^2*flushSize,maxFileSize)

其中,r为在线 Region 个数,maxFileSize由参数hbase.hregion.max.filesize指定,默认为 10G.

这里假设 flushSize 为 128M,maxFileSize 为默认的 10G,看看 split 的过程:

1
2
3
4
5
6
第一次拆分大小为:min(1*1*128M, 10G)=128M
第二次拆分大小为:min(3*3*128M, 10G)=1152M
第三次拆分大小为:min(5*5*128M, 10G)=3200M
第四次拆分大小为:min(7*7*128M, 10G)=6272M
第五次拆分大小为:min(9*9*128M, 10G)=10G
第六次拆分大小为:min(11*11*128M, 10G)=10G

可以看到当拆分第五次的时候达到了设定的最大文件10G,hbase.hregion.max.filesize设置的越大,split的上限大小就越大

两个问题

热点问题

热点问题:也就是数据都一直向一个region写,出现写热点问题

热点问题出现原因

热点问题出现的原因就是

  1. 数据倾斜:某些数据行被频繁写入,导致部分的region server承载了大量的读写负载
  2. rowkey涉及不合理

拆分合并风暴

当用户的 Region 大小以恒定的速度增长,Region 的拆分会在同一时间发生,因为同时需要压缩 Region 中的存储文件,这个过程会重写拆分后的 Region,这将会引起磁盘 I/O 上升 。

一般我们要防止这个现象要关闭hbase的自动管理拆分,手动调用hbase的拆分和合并,分散IO负载

预分区方法

手动创建

手动设置预分区

1
create 'datamanroad:Employee', 'info', 'partition1', SPLITS => ['10000','20000','30000','40000','50000']

我们其实创建了6个分区,0,10000,20000,30000,40000,50000

根据文件设置规则分区

1
2
3
4
5
6
[hadoop@hadoop100 data]$ vim splits.txt
aaaaa
bbbbb
ccccc
ddddd
eeeee
1
create 'datamanroad:Employee_beta', 'info', 'partition3', SPLITS_FILE => '/opt/data/splits.txt'

代码创建预分区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//创建表并进行预分区
public static void hBaseSplit() throws IOException {

//HBase 配置文件,配置 Zookeeper 地址,端口默认为 2181
Configuration configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", "hadoop100,hadoop101,hadoop102");

//获取连接对象
Connection connection = ConnectionFactory.createConnection(configuration);

//获取管理员对象
Admin admin = connection.getAdmin();

//自定义算法,产生一系列Hash散列值存储在二维数组中
byte[][] splitKeys = {{1,2,3,4,5}, {'a','b','c','d','e'}};

//通过 HTableDescriptor 创建表
HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("DMR_Employee"));
//添加列族
hTableDescriptor.addFamily(new HColumnDescriptor("info"));
hTableDescriptor.addFamily(new HColumnDescriptor("salary"));

//创建表,并使用自定义算法生成预分区
admin.createTable(hTableDescriptor, splitKeys);

//关闭资源
admin.close();
}