Hbase预分区

櫰木2年前技术文章616


HBase 的数据物理存储格式为多维稀疏排序 Map, 由 key 及 value 组成:

  • key 的构成: rowkey+column family+column qualifier+timestamp+type

  • value 的构成:字节形式存储

在 key 中的 rowkey 可以唯一标识一行记录,因此 HBase 的查询有以下几种实现方式:

  1. 通过 get 方式,指定 rowkey 获取唯一一条记录;

  2. 通过 scan 方式,设置 STARTROW 和 ENDROW 参数进行范围匹配;

  3. 全表扫描,即直接扫描整张表中所有行记录。

HBase 是通过 rowkey 来进行查询的,rowkey 设计的优劣会直接影响读写性能。一般 rowkey 上都会存放一些比较关键的检索信息,我们需要提前规划好数据具体要如何查询,根据查询方式进行数据存储格式的设计,避免做效率特别低的全表扫描。

那如何才能设计出既符合业务使用逻辑,又能满足系统性能需求的 rowkey 呢?

1预分区

在介绍 rowkey 设计之前,先来了解 HBase 的预分区,因为预分区跟 rowkey 设计密不可分。rowkey 设计完成后,需要通过预分区来落地实现。

1.1HBase 的 split 机制

通常 HBase 会自动处理 Region 的拆分操作,当 Region 的大小到达一定阈值后,会把过大的 Region 一分为二,之后在两个 Region 中都能继续增长数据。这就是 HBase 的 split 机制。

HBase 默认的 Region split 策略是,根据以下公式确定 split 的 maxFileSize:

min(r2flushSizemaxFileSize)

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

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

第一次拆分大小为: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 的上限大小就会越大。

在 HBase 的这个 split 的过程当中,会出现两个问题:

第一,就是我们所说的热点问题(下面会详细介绍),数据会继续往一个 Region 中写,出现写热点问题;

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

对于拆分合并风暴,通常需要关闭 HBase 的自动管理拆分,然后手动调用 HBase 的 split 和 major_compact,来分散 I/O 负载。但是其中的 split 操作同样是高 I/O 的操作。

1.2 预分区的意义

为了解决这些问题,预分区就是一种很好的方法,通常预分区可以和 rowkey 的设计结合起来使用。

所谓预分区,就是预先创建 HBase 的表分区。在 HBase 中,每一个 Region 维护着 startRowKey 与 endRowKey,如果加入的数据符合某个 Region 维护的 rowkey 范围,则该数据会交给这个 Region 进行维护。因此可以通过预分区,避免出现 split 过程中的热点问题和拆分合并风暴。

在进行预分区之前,需要明确 rowkey 的取值范围和构成逻辑,将数据要存放的分区大致规划好。分区数量建议为 RegionServer 服务器的倍数,这样能保证每个 RegionServer 上的 Region 数量尽可能一样,均衡分布。

例如,rowkey 为:a-abc001、b-abc002、c-abc003,那么预分区就可以设定为:( ,a)、[a,b)、[b,c)、[c, ).

1.3 预分区的方法

1.3.1. 手动设定预分区

可在 HBase Shell 中使用以下语句,创建表的同时手动设定预分区:

create 'default:table', 'CF', 'partition', SPLITS => []

例如,手动设定 10000 - 50000 的预分区:

create 'default:test1', 'info', 'partition1', SPLITS => ['10000','20000','30000','40000','50000']

在 HBase Web 页面上查看新建表的预分区:

iShot_2023-10-09_14.28.28.png

图1-3-1:查看手动设定的预分区

可以看到,新建的表 Employee 被预先分成了 6 个分区,每个 RegionServer 各分配到两个分区。

1.3.2. 使用十六进制序列预分区

可在 HBase Shell 中使用以下语句,创建表的同时使用十六进制序列生成预分区:

create 'default:test1', 'info', 'partition1', SPLITS => ['10000','20000','30000','40000','50000']

在 HBase Web 页面上查看新建表的预分区:

iShot_2023-10-09_14.28.28.png

图1-3-2:查看十六进制序列预分区

可以看到,新建的表test1 被预先分成了分区

相关文章

gitlab的部署

gitlab的部署

一、GitLab简介GitLab 是一个用于仓库管理系统的开源项目。使用Git作为代码管理工具,并在此基础上搭建起来的web服务。可通过Web界面进行访问公开的或者私人项目。它拥有与Github类似的...

使用clickhouse-copier迁移数据

说明clickhouse-copier是clickhouse官方提供的一个数据迁移工具。支持将clickhouse表从一个集群迁移到另外一个集群。使用clickhouse-copier有一些限制条件:...

EasyMR之Yarn资源队列管理

EasyMR之Yarn资源队列管理

设想一下,你现在所在的公司有一套线上的hadoop集群。A部门经常做一些定时的BI报表,B部门则经常使用一些软件做一些临时需求。那么他们肯定会遇到同时提交任务的场景,这个时候到底如何分配资源满足这两个...

C++ 编程:程序组成部分 & 函数 & 输入

C++ 编程:程序组成部分 & 函数 & 输入

程序结构首先从一个最简单的程序来看 C++ 程序结构:第一部分:#include <iostream> 专业名词叫:预处理器编译指令 其实效果就类似于导包; 第二部分:main() 程序的...

Datanode节点坏卷处理

Datanode节点坏卷处理

1、告知客户故障信息,确定是否有备用磁盘更换2、停止故障节点的所有角色服务3、卸载故障磁盘umount -vl /data64、等待硬件厂商更换好磁盘5、对新磁盘分区和格式化#1.磁盘分区 mkfs...

oracle v$archive_log视图过期信息清理

      在使用RMAN命令删除归档后,查询v$archived_log视图会发现name列为空了,但其他列的信息还保留,时间长了会留下很多过期的信息,影响维护工作,需要将过期的信息删除。 出现这样...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。