HBase Compaction策略

RegionServer这种类LSM存储引擎需要不断的进行Compaction来减少磁盘上数据文件的个数和删除无用的数据从而保证读性能。

RegionServer后台有一组负责flush region的线程(MemStoreFlusher),每次从flushQueue中拿出一个flush region请求,会检查这个region是否有某个store包含的storefile个数超过配置

hbase.hstore.blockingStoreFiles,默认7,如果超过,说明storefile个数已经到了会影响读性能的地步,那么就看这个flush region

请求是否已经有blockingWaitTime(hbase.hstore.blockingWaitTime,默认90s)没有执行了,如果是,这时候需要立即执行flush region,为了防止OOM。如果没有超过blockingWaitTime,那么先

看看region是否需要分裂,如果不需要,则向后台的CompactionSplitThread请求做一次

Compaction(从这里可以看出,split优先级比compaction高),然后重新将这个flush region加入

flushQueue,延后做flush.

重点看Compaction

Compaction以store为单位,

CompactSplitThread会为region的每个store生成一个CompactionRequest.

一个Compaction根据它包含的storefile的总大小,可以分为

large compaction和small compaction,这两种compaction分别被两个不同的线程池处理。

系统一般认为small compaction占大多数,所以上文中由于storefile过多系统自动触发的system compaction 默认放入small compaction池子中处理.

//系统自动触发的system compaction,selectNow参数为false,实际选取待compact的
filelist过程延后在CompactionRunner中做.
if (selectNow) {
// 通过hbase shell触发的major compaction,selectNow为true.这里进行实际的选取待compact filelist操作
compaction = selectCompaction(r, s, priority, request);
if (compaction == null) return null; // message logged inside
}
// We assume that most compactions are small. So, put system compactions
//into small pool; we will do selection there, and move to large pool if //necessary. long size = selectNow ? compaction.getRequest().getSize() : 0; // 从这里可以看出,用户外部触发的compaction默认放入small compaction线程池中处理,并且
// system compaction 也会放入small compaction线程池中,后续真正执行
// system compaction时,会根据选出的storefile的总大小来决定最终放入large还是small线程池
ThreadPoolExecutor pool = (!selectNow && s.throttleCompaction(size))? largeCompactions : smallCompactions;
pool.execute(new CompactionRunner(s, r, compaction, pool));

看看执行compaction过程的CompactionRunner任务。

 // Common case - system compaction without a file selection. Select now.
// system compaction 还没有选择待compact的filelist,为null
if (this.compaction == null) {
int oldPriority = this.queuedPriority;
this.queuedPriority = this.store.getCompactPriority();
if (this.queuedPriority > oldPriority) {
// Store priority decreased while we were in queue (due to some other compaction?),
// requeue with new priority to avoid blocking potential higher priorities.
this.parent.execute(this);
return;
}
try {
// 选择storefile
this.compaction = selectCompaction(this.region, this.store, queuedPriority, null);
} catch (IOException ex) {
LOG.error("Compaction selection failed " + this, ex);
server.checkFileSystem();
return;
}
if (this.compaction == null) return; // nothing to do
// Now see if we are in correct pool for the size; if not, go to the correct one.
// We might end up waiting for a while, so cancel the selection.
assert this.compaction.hasSelection();
// 判断这次compaction放入small还是large池中执行
ThreadPoolExecutor pool = store.throttleCompaction(
compaction.getRequest().getSize()) ? largeCompactions : smallCompactions;
// system compaction应该放入large池
if (this.parent != pool) {
this.store.cancelRequestedCompaction(this.compaction);
this.compaction = null;
this.parent = pool;
// 在large池子中执行
this.parent.execute(this);
return;
}
}

large compaction和small compaction分界线由

hbase.regionserver.thread.compaction.throttle参数决定,如果没有设置,

默认为2 * hbase.hstore.compaction.max * hbase.hregion.memstore.flush.size

全部取默认值等于2*10*128MB = 2.5GB

从以上可以看出,system compaction默认放入small池,当选出storefile list

后,再根据size去判断最终放入small还是large线程池中执行.

对于外部触发的compaction,放入small中执行.

选定池子后,下面看每个store compaction具体的步骤

两个步骤:

  1. 根据某种策略生成compact的目标storefile集合
  2. 进行compaction

这两步都在CompactionRunner这个runnable任务中完成。

这里主要说第一个步骤:入口在HStore::requestCompaction.

首先创建storeEngine相应的CompactionContext,这个context用来存各种compact相关的信息,

最重要的就是CompactionRequest,作为上面第二个步骤的输入. HBase 0.98主要有两种存储引擎,DefaultStoreEngine和StripeStoreEngine,这里的存储引擎主要是管理磁盘上的storefile文件和flush 内存中的snapshot memstore到磁盘。StripStoreEngine比较特别,

一个snapshot memstore刷到磁盘上有可能多于一个storefile文件,这里不讨论.大部分人都使用默认的storeEngine.

其次,创建完context后,然后调用compactionPolicy的selectCompaction(),将store下面的所有storefile传进去,供其挑选.HBase的compaction policy可通过

配置项hbase.hstore.defaultengine.compactionpolicy.class配置,默认是

ExploringCompactionPolicy.class

下面看selectCompaction(),主要有几个步骤:

  1. 从store下面的storefiles中过滤掉比正在compacting的storefilelist中最新的storefile更老的storefile(输入的storefile按照如下规则排序)

     public static final Comparator<StoreFile> SEQ_ID =
    Ordering.compound(ImmutableList.of(
    Ordering.natural().onResultOf(new GetSeqId()),
    Ordering.natural().onResultOf(new GetFileSize()).reverse(),
    Ordering.natural().onResultOf(new GetBulkTime()),
    Ordering.natural().onResultOf(new GetPathName())
    ));

seq id是storefile对应的snapshot memstore在flush时,从region内部的全局递增计

数器sequenceId中取到的,可以看到,seq id越大的storefile越新.对多个文件进行compact后产生的新的storefile的seq id被设置为多个文件中最大的seq id

  1. 如果不是major compaction,就检查:如果配置了删除ttl到期的storefile,并且ttl是一个有限的值,那么这次compaction只会选ttl到期的storefile,如果目前确实存在ttl过期的storefile,则这次compaction选取的文件列表就是这些过期的storefile,选取文件流程结束,CompactionRequest产生。如果没有配置,则过滤掉文件大小大于配置值

    hbase.hstore.compaction.max.size(默认是 Long.MAX_VALUE)的storefile(实际上,这块实现有问题)
  2. 根据一些规则和参数,判断是否升级为major compaction,比较烦,直接贴代码
 // Force a major compaction if this is a user-requested major compaction,
// or if we do not have too many files to compact and this was requested
// as a major compaction.
// Or, if there are any references among the candidates.
boolean majorCompaction = (
(forceMajor && isUserCompaction)
|| ((forceMajor || isMajorCompaction(candidateSelection))
&& (candidateSelection.size() < comConf.getMaxFilesToCompact()))
|| StoreUtils.hasReferences(candidateSelection)
);
- 如果不是,那么这次compaction是一个minor compaction,做以下几件事
- 过滤掉bulk load的storefile
- 应用ExploringCompactionPolicy重写的applyCompactionPolicy方法,挑选

storefile的思想是:枚举所有的n个连续文件,n位于[hbase.hstore.compaction.min(默认3), hbase.hstore.compaction.max(默认10)]之间, 这是对于minor compaction的文件个数的限制。并且n个连续的文件大小总和不能超过hbase.hstore.compaction.max.size(默认MAX_VALUE),并且n个文件的大小之间的"方差"不能太大. 最后选出n个文件,选择的原则是:删除最多的文件同时这些文件的

大小总和小(消耗更少的磁盘IO)

- 检查是否选出来的storefile个数超过hbase.hstore.compaction.max,如果超过,并且

这只是minor compaction,则从storefile文件集合尾部将多余的storefile过滤掉,如果超过但是是major compaction并且是用户发起的,则不过滤.至此,这次compact的storefile集合产生,结束。

至此,第一个步骤结束,compact的目标storefile选出.

参考资料

https://github.com/apache/hbase/tree/0.98

HBase Compaction详解的更多相关文章

  1. Mac下安装HBase及详解

    Mac下安装HBase及详解 1. 千篇一律的HBase简介 HBase是Hadoop的数据库, 而Hive数据库的管理工具, HBase具有分布式, 可扩展及面向列存储的特点(基于谷歌BigTabl ...

  2. Hbase存储详解

    转自:http://my.oschina.net/mkh/blog/349866 Hbase存储详解 started by chad walters and jim 2006.11 G release ...

  3. 大数据学习系列之五 ----- Hive整合HBase图文详解

    引言 在上一篇 大数据学习系列之四 ----- Hadoop+Hive环境搭建图文详解(单机) 和之前的大数据学习系列之二 ----- HBase环境搭建(单机) 中成功搭建了Hive和HBase的环 ...

  4. HUE配置文件hue.ini 的hbase模块详解(图文详解)(分HA集群和非HA集群)

    不多说,直接上干货! 我的集群机器情况是 bigdatamaster(192.168.80.10).bigdataslave1(192.168.80.11)和bigdataslave2(192.168 ...

  5. HBase配置项详解

    hbase.tmp.dir:本地文件系统的临时目录,默认是java.io.tmpdir/hbase−java.io.tmpdir/hbase−{user.name}: hbase.rootdir:hb ...

  6. HBase——强一致性详解

    Hbase是一个强一致性数据库,不是“最终一致性”数据库,官网给出的介绍: “Strongly consistent reads/writes: HBase is not an "event ...

  7. hbase配置详解(转)

    转自:http://www.cnblogs.com/viviman/archive/2013/03/21/2973539.html 1 准备工作 因为我只有一台机器,所以,一切都成为了伪分布,但是,其 ...

  8. Sqoop import加载HBase案例详解

    简单写一下如何将订单表sqoop到hbase表中的步骤. 下表: 1.通过hbase shell 打开hbase. 2.创建一个hbase表 create 'so','o' 3.将so表的数据导入到h ...

  9. HBase API详解

    一.Java API和HBase数据模型的关系 在Java中,与HBase数据库存储管理相关的类包括HBaseAdmin.HBaseConfiguration.HTable.HTableDescrip ...

随机推荐

  1. log4j:WARN No appenders could be found for logger (org.apache.hadoop.metrics2.lib.MutableMetricsFactory). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.o

    上面的报错是在本地java调试(windows) hadoop集群 出现的 解决方案: 在resources文件夹下面创建一个文件log4j.properties(这个其实hadoop安装目录下的 e ...

  2. 【数组】4Sum

    题目: Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = ...

  3. UTF8最好不要带BOM

    摘自:http://www.cnblogs.com/findumars/p/3620078.html   几周前还在为BOM的问题苦恼着...正如@梁海所说,“不含 BOM 的 UTF-8 才是标准形 ...

  4. web前端html快速入门

    HTML 学前端之间不得不知道一个网站:http://www.w3school.com.cn/ 网上有很多教程关于前端的,写的特别详细,也写的特别好.我们应该要自已理解,一些相应的前端的知识,不能只是 ...

  5. 解决MySQL联表时出现字符集不一样

    mysql 建表时都会设置表的字符集和排序规则,通常是 utf8,不过我这边习惯建表的字符集是 utf8mb4,排序规则是 utf8mb4_unicode_ci.有些 utf8mb4 的表默认排序规则 ...

  6. onsubmit解惑

    1.onsubmit的位置: onsubmit只存在于html <form>中,js的form中 2.submit与onsubmit的区别 发生顺序:onsubmit -> subm ...

  7. Linux的用户(组),权限,文件精妙的三角关系,和强大的帮助系统

    在linux中一切都是文件(文件夹和硬件外设是特殊的文件),如果有可能尽量使用文本文件.文本文件是人和机器能理解的文件,也成为人和机器进行 交流的最好途径.由于所有的配置文件都是文本,所以你只需要一个 ...

  8. Linux 文件内容查看工具介绍-cat,less,more,tail,head

    Linux 文件内容查看工具介绍 作者:北南南北来自:LinuxSir.Org摘要: 本文讲述几种常用文件内容的查看工具,比如cat.more.less.head.tail等,把这些工具最常用的参数. ...

  9. 第一章 面向对象软件工程与UML

    这个OOAD讲的都是很抽象的东西!老师说这个在现在的学习中用到的不是很多,但是以后出去工作的时候就会常用到的. 首先来了解OOAD是讲什么的. OOAD:Object Oriented Analysi ...

  10. rails常用验证方法

    validates_presence_of       :login,  :message => "用户名不能为空!" validates_length_of         ...