分析hbase的split流程,同样地我们先从regionserver中的相应线程作为突破口,依次分析split的触发条件和split的执行实现。
split的触发条件:
我们在compact流程分析中讲解过,hbase的regionserver中维护着一个CompactSplitThread类型的变量,所有的compact/split请求都会交给该变量处理,前面我们分析了compact在CompactSplitThread中的处理,同样的,我们接下来将会分析split是如何在CompactSplitThread中被处理的。首先还是看CompactSplitThread中定义的几个与split相关的变量。
private final ThreadPoolExecutor longCompactions; //long合并线程池
private final ThreadPoolExecutor shortCompactions; //short合并线程池
private final ThreadPoolExecutor splits; //split线程池
private final ThreadPoolExecutor mergePool; //merge线程池
private int regionSplitLimit;
需要注意的是最后一个整型变量regionSplitLimit,它定义了一个regionserver所持有的最大region总数,如果region的数量超过了它的限制,则split不会再发生。该变量的值由hbase.regionserver.regionSplitLimit配置,默认是1000;splits是该regionserver用于参与split的线程池,线程池中的线程数量由“hbase.regionserver.thread.split”配置,默认是1。
region发生split时,调用方会调用CompactSplitThread中的requestSplit方法,该方案将split请求包装成一个Runnable的SplitRequest对象放入前文所说的线程池split中去执行。
this.splits.execute(new SplitRequest(r, midKey, this.server));
分析requestSplit方法的调用时机就可以理出region发生split行为的时间。我们直接列出结果如下:
第一种方式是region发生compact之后,此时会形成比较大的文件,split会在这个时候被调用;
第二种方式是region发生flush的时候,这一部分的代码如下:
lock.readLock().lock();
try {
notifyFlushRequest(region, emergencyFlush);
FlushResult flushResult = region.flush(forceFlushAllStores);
boolean shouldCompact = flushResult.isCompactionNeeded();
// We just want to check the size
boolean shouldSplit = ((HRegion)region).checkSplit() != null;
if (shouldSplit) {
this.server.compactSplitThread.requestSplit(region);