这是我参与【第四届青训营】笔记创造活动的第十三天。
Region Split 热点切分
HBase支持的几种常见region split触发策略如下:
- ConstantSizeRegionSplitPolicy:0.94版本前默认切分策略。一个region中最大store的大小大于设置阈值之后触发切分。阈值(hbase.hregion.max.filesize)设置较大对大表比较友好,但是小表就有可能不会触发分裂,极端情况下可能就1;设置较小则对小表友好,但一个大表就会在整个集群产生大量的region。
- IncreasingToUpperBoundRegionSplitPolicy: 0.94版本~2.0版本默认切分策略。总体来看和ConstantSizeRegionSplitPolicy思路相同,一个region中最大store大小大于设置阈值就会触发切分。阈值计算公式 :(#regions) * (#regions) * (#regions) * flush size * 2,最大不超过用户设置的MaxRegionFileSize。这种切分策略很好的弥补了ConstantSizeRegionSplitPolicy的短板,能够自适应大表和小表。
- SteppingSplitPolicy: 2.0版本默认切分策略。如果region个数等于1,切分阈值为flush size * 2,否则为MaxRegionFileSize。这种切分策略对于大集群中的大表、小表会比IncreasingToUpperBoundRegionSplitPolicy更加友好,小表不会再产生大量的小region,而是适可而止。
Region split 步骤如下:
-
找到切分点splitpoint,一般是整个region中最大store中的最大HFile文件中最中心的一个block的首个rowkey。
-
HBase将整个切分过程包装成了一个事务,意图能够保证切分事务的原子性。整个分裂事务过程分为三个阶段:prepare – execute – (rollback)
- prepare阶段:在内存中初始化两个子region,具体是生成两个HRegionInfo对象,包含tableName、regionName、startkey、endkey等。同时会生成一个transaction journal,这个对象用来记录切分的进展
-
execute阶段:
-
regionserver 更改ZK节点 /region-in-transition 中该region的状态为SPLITING。
- master通过watch节点/region-in-transition检测到region状态改变,并修改内存中region的状态,在master页面RIT模块就可以看到region执行split的状态信息。
- 在父存储目录下新建临时文件夹.split保存split后的daughter region信息。
- 关闭parent region:parent region关闭数据写入并触发flush操作,将写入region的数据全部持久化到磁盘。此后短时间内客户端落在父region上的请求都会抛出异常NotServingRegionException。
- 核心分裂步骤:在.split文件夹下新建两个子文件夹,称之为daughter A、daughter B,并在文件夹中生成reference文件,分别指向父region中对应文件。生成reference文件的日志如下:
reference文件名前半段是父region对应的HFile文件名,后半段是父region的目录名。 reference文件内容包括切分点的rowkey,和一个boolean值表示该子文件夹是上半还是下半部分。
- 父region分裂为两个子region后,将daughter A、daughter B拷贝到HBase根目录下,形成两个新的region。
- parent region通知修改 hbase.meta 表后下线,不再提供服务。下线后parent region在meta表中的信息并不会马上删除,而是标注split列、offline列为true,并记录两个子region。
- 开启daughter A、daughter B两个子region。通知修改 hbase.meta 表,正式对外提供服务。
rollback阶段:如果execute阶段出现异常,则执行rollback操作。为了实现回滚,整个切分过程被分为很多子阶段,回滚程序会根据当前进展到哪个子阶段清理对应的垃圾数据。