hbase中如何使用split策略

这篇文章主要为大家展示了“hbase中如何使用split策略”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“hbase中如何使用split策略”这篇文章吧。

创新互联公司专注于白山网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供白山营销型网站建设,白山网站制作、白山网页设计、白山网站官网定制、重庆小程序开发服务,打造白山网络公司原创品牌,更为您提供白山网站排名全网营销落地服务。

    在这个版本中使用的split策略是IncreasingToUpperBoundRegionSplitPolicy。确切来说他是0.94版本以后的策略。类为org/apache/hadoop/hbase/regionserver/IncreasingToUpperBoundRegionSplitPolicy.java 
    首先看一下 configureForRegion 方法,其中的initialSize 在以后会用到。这个方法其实主要目的也就是在初始化initialSize 

@Override
  protected void configureForRegion(HRegion region) {
    super.configureForRegion(region);
    Configuration conf = getConf();
    //如果设置了hbase.increasing.policy.initial.size,则使用用户设置的
    this.initialSize = conf.getLong("hbase.increasing.policy.initial.size", -1);
    if (this.initialSize > 0) {
      return;
    }
    //如果没有设置,看hbase.hregion.memstore.flush.size有没有
    //如果设置了则initialSize=2*hbase.hregion.memstore.flush.size,
    //如果没有则使用默认的1024*1024*128L  (128M)
    HTableDescriptor desc = region.getTableDesc();
    if (desc != null) {
      this.initialSize = 2*desc.getMemStoreFlushSize();
    }
    if (this.initialSize <= 0) {
      this.initialSize = 2*conf.getLong(HConstants.HREGION_MEMSTORE_FLUSH_SIZE,
        HTableDescriptor.DEFAULT_MEMSTORE_FLUSH_SIZE);
    }
  }

如果配置默认,这个方法将initialSize 初始化为2*hbase.hregion.memstore.flush.size
再来看看其他的方法,有一个方法叫shouldSplit,顾名思义就是判断能不能split。

@Override
  protected boolean shouldSplit() {
    if (region.shouldForceSplit()) return true;
    boolean foundABigStore = false;
    //得到同张表的在线region个数
    // Get count of regions that have the same common table as this.region
    int tableRegionsCount = getCountOfCommonTableRegions();
    //得到分割的阀值
    // Get size to check
    long sizeToCheck = getSizeToCheck(tableRegionsCount);
    //检查每一个store,如果有不能split的则此次判断为false
    for (Store store : region.getStores().values()) {
      // If any of the stores is unable to split (eg they contain reference files)
      // then don't split
    	//如果当前region不能分割,则返回false
      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=" + size + ", sizeToCheck=" + sizeToCheck +
          ", regionsWithCommonTable=" + tableRegionsCount);
        foundABigStore = true;
      }
    }

    return foundABigStore;
  }

其中long sizeToCheck = getSizeToCheck(tableRegionsCount);这句很重要,跟进去查看

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(),
        this.initialSize * tableRegionsCount * tableRegionsCount * tableRegionsCount);
  }

这是一个三目运算,如果这个table中在线的region个数为0或则大于100,则使用getDesiredMaxFileSize()方法得到这个阀值,否则就使用getDesiredMaxFileSize()得到的阀值和initialSize * (tableRegionsCount的三次方)中小的那一个,在跟进去getDesiredMaxFileSize方法看看
 

long getDesiredMaxFileSize() {
    return desiredMaxFileSize;
  }

这个方法是ConstantSizeRegionSplitPolicy中的方法,别觉得奇怪,因为IncreasingToUpperBoundRegionSplitPolicy extends ConstantSizeRegionSplitPolicy,这个找不到线索就看看这个类,然后找到了如下代码

private long desiredMaxFileSize;

  @Override
  protected void configureForRegion(HRegion region) {
    super.configureForRegion(region);
    Configuration conf = getConf();
    HTableDescriptor desc = region.getTableDesc();
    if (desc != null) {
      this.desiredMaxFileSize = desc.getMaxFileSize();
    }
    //设置desiredMaxFileSize = hbase.hregion.max.filesize的大小默认是10G
    if (this.desiredMaxFileSize <= 0) {
      this.desiredMaxFileSize = conf.getLong(HConstants.HREGION_MAX_FILESIZE,
        HConstants.DEFAULT_MAX_FILE_SIZE);
    }
    //如果设置了hbase.hregion.max.filesize.jitter  则desiredMaxFileSize做个抖动
    float jitter = conf.getFloat("hbase.hregion.max.filesize.jitter", Float.NaN);
    if (!Float.isNaN(jitter)) {
      this.desiredMaxFileSize += (long)(desiredMaxFileSize * (RANDOM.nextFloat() - 0.5D) * jitter);
    }
  }

原来如果设置了hbase.hregion.max.filesize.jitter,则用HREGION_MAX_FILESIZE + HREGION_MAX_FILESIZE*随机小数*hbase.hregion.max.filesize.jitter,其中jitter默认为0.5,HREGION_MAX_FILESIZE 其实就是hbase.hregion.max.filesize,默认是10G,至于为什么抖动,有的人说是为了防止重启regionServer时进行大量的major compact,这种说法我暂时不明白,先放一放。

回到shouldSplit方法中,我们看看canSplit方法做了什么?
 

@Override
  public boolean canSplit() {
    this.lock.readLock().lock();
    try {
      // Not split-able if we find a reference store file present in the store.
      boolean result = !hasReferences();
      if (!result && LOG.isDebugEnabled()) {
        LOG.debug("Cannot split region due to reference files being there");
      }
      return result;
    } finally {
      this.lock.readLock().unlock();
    }
  }

很简单,就是看看有没有引用文件,如果有则不能split,如果没有则可以,再次回到shouldSplit方法,可以看到如果当前的store的大小大于刚刚计算出的阀值,则返回true,算是通过split的判断了。

好的,来总结一下:

hbase对一个region切分,有几个条件:
1、如果是用户请求切分,则不管什么情况都可以切分。
2、如果非用户请求,并且这个region中任意store含有引用文件,则不切分
3、如果不是用户请求,也没有引用文件,则判断每个store的大小,只要其中有一个大于阀值,则切分。这个阀值在上面已经有说到。

说下这个策略的含义
0.94版本之前使用的是ConstantSizeRegionSplitPolicy策略,此策略只是大于一个基本固定的阀值就允许split,而现在的策略则是store大小大于一个变化的阀值就允许split,什么意思呢,举个例子,当hbase相关split的属性都没有配置,采用默认,一张表刚建立,默认情况只有1个region,那么逻辑上是当这个region的store大小超过 1*1*1*flushsize = 128M(没有自己设置flushSize)时 才会允许split,如果达到这个值切分后,会有两个region,其中一个region中的某个store大小大于 2*2*2*flushsize = 512M 时,则允许split,如此计算下去,直到这个大小超过了hbase.hregion.max.filesize+ hbase.hregion.max.filesize*随机小数*hbase.hregion.max.filesize.jitter才允许split,基本也就固定了,如果粗劣的计算可以把这个hbase.hregion.max.filesize的大小作为最后的阀值,默认是10G,也就说当这个阀值变化到10G,这个阀值就基本上不再变化。
 

这种思想使得阀值达到一个基本固定的值之前先做了几次split,而这几次split的数据量很少,对hbase的影响也没有那么大,而且相当于数据导入量不大的时候就做了一次“预分region”,在一定意义上减少了以后的热点region的发生。

以上是“hbase中如何使用split策略”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注创新互联行业资讯频道!


网页标题:hbase中如何使用split策略
标题来源:http://pwwzsj.com/article/picjeo.html