HBase2.x精通:结合源码讲解Region的三种Spilt策略

一、概述

最近 在工作中接触到split,于是查看了这块的源代码,先看到了split的策略,今天就说说这个吧; 这里我是基于HDP版本的Hadoop集群,对应的HBase的版本为2.2.1,后续的分析都是基于该版本的源码做的分析, HBase-2.x支持7种Region自动拆分的策略,继承关系如下图所示:

二、针对这几种默认拆分策略做单独的说明。

1.RegionSplitPolic y

RegionSplitPolicy是一个抽象类,其作为所有Region拆分策略的父类。在0.94版本以前,默认的拆分策略是ConstantSizeRegionSplitPolicy,在0.94版本以后,默认的策略为IncreasingToUpperBoundRegionSplitPolicy ,从2.0.0版本开始,默认的策略为SteppingSplitPolicy。

在基类RegionSplitPolicy的源码中可以看到各个HBase版本默认的Spilt策略:

/**

* A split policy determines when a Region should be split.

*

* @see SteppingSplitPolicy Default split policy since 2.0.0

* @see IncreasingToUpperBoundRegionSplitPolicy Default split policy since

* 0.94.0

* @see ConstantSizeRegionSplitPolicy Default split policy before 0.94.0

*/

@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)

public abstract class RegionSplitPolicy extends Configured {

......................

}

2.ConstantSizeRegionSplitPolicy

0.94版本前默认切分策略。这是最容易理解但也最容易产生误解的切分策略,从字面意思来看,当region大小大于某个阈值(由参数hbase.hregion.max.filesize控制)之后就会触发切分,实际上并不是这样,真正实现中这个阈值是对于某个store来说的,即一 个region中最大store的大小大于设置阈值之后才会触发切分 。另外一个大家比较关心的问题是这里所说的store大小是压缩后的文件总大小还是未压缩文件总大小,实际实现中store大小为压缩后的文件大小(采用压缩的场景)。

ConstantSizeRegionSplitPolicy相对来来说最容易想到,但是在生产线上这种切分策略却有相当大的弊 端:切分策略对于大表和小表没有明显的区分。阈值(hbase.hregion.max.filesize)设置较大对大表比较友好,但是小表就有可能不会触发分裂,极端情况下可能就1个,这对业务来说并不是什么好事。如果设置较小则对小表友好,但一个大表就会在整个集群产生大量的region,这对于集群的管理、资源使用、failover来说都不是一件好事。

源码中 有一个方法叫shouldSplit,顾名思义就是判断能不能split ,ConstantSizeRegionSplitPolicy类中对应的代码如下:

@Override

protected boolean shouldSplit() {

boolean force = region.shouldForceSplit();

boolean foundABigStore = false;


for (HStore store : region.getStores()) {

// If any of the stores are unable to split (eg they contain reference files)

// then don't split

//看看有没有引用文件,如果有则不能split

if ((!store.canSplit())) {

return false;

}

// Mark if any store is big enough

//这里就是判断是否大于一个固定值,这里默认就是10G,大于这个值就进行Split,不过hbase有个参数hbase.hregion.max.filesize.jitter

//设置了一个抖动值,这里我没太理解明白,可暂时不考虑,直接认为达到一个固定值10G,

//进行了region的分裂

if (store.getSize() > desiredMaxFileSize) {

foundABigStore = true;

}

}

return foundABigStore || force;

}

3.IncreasingToUpperBoundRegionSplitPolicy

0.94版本~2.0版本默认切分策略。这种切分策略微微有些复杂,总体来看和ConstantSizeRegionSplitPolicy思路相同,一个region中最大store大小大于设置阈值就会触发切分。但是这个阈值并不像ConstantSizeRegionSplitPolicy是一个固定的值,而是会在一定条件下不断调整,调整规则和 region所属表在当前regionserver上的region个数有关系 :(#regions) * (#regions) * (#regions) * flush size * 2,当然阈值并不会无限增大, 最大值为用户设置的MaxRegionFileSize。

这种切分策略很好的弥补了ConstantSizeRegionSplitPolicy的短板,能够自适应大表和小表。而且在大集群条件下对于很多大表来说表现很优秀,但并不完美,这种策略下很多小表会在大集群中产生大量小region,分散在整个集群中。而且在发生region迁移时也可能会触发region分裂。

IncreasingToUpperBoundRegionSplitPolicy类中是否分裂判断函数 shouldSplit 的代码如下:

@Override

protected boolean shouldSplit() {

boolean force = region.shouldForceSplit();

boolean foundABigStore = false;

// Get count of regions that have the same common table as this.region

int tableRegionsCount = getCountOfCommonTableRegions();

//这里就是是否分裂的关键判断逻辑

long sizeToCheck = getSizeToCheck(tableRegionsCount);


for (HStore store : region.getStores()) {

// If any of the stores is unable to split (eg they contain reference files)

// then don't split

if (!store.canSplit()) {

return false;

}


// Mark if any store is big enough

long size = store.getSize();

if (size > sizeToCheck) {

LOG.debug("ShouldSplit because " + store.getColumnFamilyName() +

" size=" + StringUtils.humanSize(size) +

", sizeToCheck=" + StringUtils.humanSize(sizeToCheck) +

", regionsWithCommonTable=" + tableRegionsCount);

foundABigStore = true;

}

}


return foundABigStore || force;

}

这里关键判断逻辑在函数getSizeToCheck中,代码如下:

/**

* @return Region max size or {@code count of regions cubed * 2 * flushsize},

* which ever is smaller; guard against there being zero regions on this server.

*/

protected long getSizeToCheck(final int tableRegionsCount) {

// safety check for 100 to avoid numerical overflow in extreme cases

return tableRegionsCount == 0 || tableRegionsCount > 100

? getDesiredMaxFileSize()

: Math.min(getDesiredMaxFileSize(),

initialSize * tableRegionsCount * tableRegionsCount * tableRegionsCount);

}

这是一个三目运算,如果这个table中在线的region个数为0或则大于100,则使用getDesiredMaxFileSize()方法得到这个阀值,否则就使用getDesiredMaxFileSize()得到的阀值和initialSize * (tableRegionsCount的三次方)中小的那一个。函数 getDesiredM axFileSize 获取的可以理解成参数hbase.hregion.max.filesize配置的大小,默认是10G,为了更方便理解分裂的过程,这里举个例子:

比如我们 hbase.hregion.max.fil esize 默认配置的是10G,要想达到10G分裂的标准,前期需要经过以下4次拆分过程:

第一次split:1^3 * 128*2= 256MB

第二次split:2^3 * 128*2= 2048MB

第三次split:3^3 * 128*2 = 6912MB

第四次split:4^3 * 128*2 = 16384MB > 10GB,因此取较小的值10GB

后面每次split的size都是10GB了。

4.SteppingSplitPolicy

2.0版本以后默认切分策略。这种切分策略的切分阈值又发生了变化,相比IncreasingToUpperBoundRegionSplitPolicy简单了一些,依然和待分裂region所属表在当前regionserver上的region个 数有关系,如果只有1个Region的情况下,那第1次的拆分就是256M,后续则按配置的拆分文件大小(hbase.hregion.max.filesize默认值是10G)作为Region拆分标准。

在IncreasingToUpperBoundRegionSplitPolicy策略中,针对大表的拆分表现很不错,但是针对小表会产生过多的Region,SteppingSplitPolicy则将小表的Region控制在一个合理的范围,对大表的拆分也不影响。

SteppingSplitPolicy是IncreasingToUpperBoundRegionSplitPolicy的子类,其总共源码只有几行,如下:

/**

* Licensed to the Apache Software Foundation (ASF) under one

* or more contributor license agreements. See the NOTICE file

* distributed with this work for additional information

* regarding copyright ownership. The ASF licenses this file

* to you under the Apache License, Version 2.0 (the

* "License"); you may not use this file except in compliance

* with the License. You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package org.apache.hadoop.hbase.regionserver;


import org.apache.yetus.audience.InterfaceAudience;


@InterfaceAudience.Private

public class SteppingSplitPolicy extends IncreasingToUpperBoundRegionSplitPolicy {

/**

* @return flushSize * 2 if there's exactly one region of the table in question

* found on this regionserver. Otherwise max file size.

* This allows a table to spread quickly across servers, while avoiding creating

* too many regions.

*/

@Override

protected long getSizeToCheck(final int tableRegionsCount) {

return tableRegionsCount == 1 ? this.initialSize : getDesiredMaxFileSize();

}


}


三、Split策略设置

Region拆分策略可以全局统一配置,也可以为单独的表指定拆分策略,下面整理了以下几种常用Split策略设置方法:

1.HBase的全局Spilt策略,可在hbase-site.xml添加如下属性:

<property>

<name>hbase.regionserver.region.split.policy</name>

<value>org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy</value>

</property>

2.使用JavaApi设置某个表的Split策略,代码如下:

HTableDescriptor tableDesc = new HTableDescriptor("table");

tableDesc.setValue(HTableDescriptor.SPLIT_POLICY, ConstantSizeRegionSplitPolicy.class.getName());

tableDesc.addFamily(new HColumnDescriptor(Bytes.toBytes("info")));

admin.createTable(tableDesc);

3.可在hbase shell控制台中设置某个表的Split策略( 常用 ),命令如下:

hbase> create 'table1', {METADATA => {'SPLIT_POLICY' => 'org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy'}},{NAME => 'info'}

4.用户也可在Configuration设置全局的Split策略,代码如下:

private static Configuration conf = HBaseConfiguration.create();

conf.set("hbase.regionserver.region.split.policy", "org.apache.hadoop.hbase.regionserver.SteppingSplitPolicy");

5.上面3中hbase shell控制台命令的设置,可以 通过使用的HBaseConfiguration或按表进行全局设置 ,代码如下:

HTableDescriptor hTableDesc= ...;

hTableDesc.setValue(HTableDescriptor.SPLIT_POLICY, MyCustomSplitPolicy.class.getName());

这里只介绍了HBase的三种默认的Split策略,其他的几种策略不太常用,有兴趣的可以去了解一下,这里不再讲解,感谢关注!!!

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章