关于hbase的compact意义及其应用背景已经有很多文章做了描述,这里不再赘述,本文以1.1.2背景的hbase为例,从源码中分析hbase中compact请求发出到接受处理的流程,限于作者水平有限,分析中可能有疏漏或者错误的地方,希望大家指正,一起学习提高。
从regionserver开始分析compact的流程,regionserver初始化的时候会初始化两个与compact相关的线程分别是compactSplitThread和compactionChecker。其中compactionChecker用于周期性地检查当前是否有compact请求,检查周期由参数threadWakeFrequency控制,默认值是10s,也可以在参数hbase.server.thread.frequency中配置。另一个变量compactSplitThread负责该region server上的compact/split请求具体执行,它的内部定义了如下四个线程池:
private final ThreadPoolExecutor longCompactions; //long合并线程池
private final ThreadPoolExecutor shortCompactions; //short合并线程池
private final ThreadPoolExecutor splits; //split线程池
private final ThreadPoolExecutor mergePool; //merge线程池
不同的请求交由不同的线程池来处理,我们关注在compact上,这里区分出long合并和short合并两个不同类型的线程池。此外compactSplitThread中还定义了一个CompactionRunner类型的内部类,该内部类包含了CompactionContext、region、store等成员变量,并实现了Runnable接口,可以看出就是在CompactionRunner中执行了具体的compact操作。
通过对以上两个变量的简单分析,我们可以大概看到compact的概貌:compactionChecker周期性地检查是否有compact请求,如果出现了compact请求,那么将请求以及请求的周边信息一起包装成CompactionContext,将CompactionContext交付给regionserver的compactSplitThread,compactSplitThread会根据compact的类型为它分配合适的线程池,并包装成CompactionRunner交给线程池,线程池调度CompactionRunner,执行它的run方法,完成compact操作。
下面我们从代码入手印证上面的猜想,并就一些细节逐渐展开丰富。下文的讲述分两个角度展开,分别是compact请求的发起和compact动作的执行,在发起机制的讲解中,我们会同时讲述compact文件的筛选原则。
compact请求的发起机制:
compactionChecker周期执行的动作在它的chore方法中定义,chore方法的主要代码如下所示:
protected void chore() {
for (Region r : this.instance.onlineRegions.values()) {
if (r == null)
continue;
for (Store s : r.getStores()) {
try {
long multiplier = s.getCompactionCheckMultiplier();
assert multiplier > 0;
if (iteration % multiplier != 0) continue;
if (s.needsCompaction()) {
// Queue a compaction. Will recognize if major is needed.
this.instance.compactSplitThread.requestSystemC