flush请求的发出:
HRegion会调用requestFlush()触发flush行为,flush发生在每一处region可能发生变化的地方,包括region有新数据写入,客户端调用了put/increment/batchMutate等接口。
首先,hbase.hregion.memstore.block.multiplier是个乘数因子,默认值是4,该值会乘上hbase.hregion.memstore.flush.size配置的值(128M),如果当前region上memstore的值大于上述两者的乘积,则该当前region的更新(update)会被阻塞住,对当前region强制发起一个flush。
其次,还有一处要求是整个regionServer上所有memstore的大小之和是否超过了整个堆大小的40%,如果超过了则会阻塞该regionserver上的所有update,并挑选出占比较大的几个region做强制flush,直至降到lower limit以下。
最后,当某个regionserver上的所有WAL文件数达到hbase.regionserver.max.logs(默认是32)时,该regionserver上的memstores会发生一次flush,以减少wal文件的数目,此时flush的目的是控制wal文件的个数,以保证regionserver的宕机恢复时间可控。
flush请求的处理流程:
hbase中flush请求的处理流程简化后如下图中所示,图片选自参考链接,这里逐个展开源码中的细节做介绍:
HRegion中requestFlush()的源代码如下所示:
private void requestFlush() { //通过rsServices请求flush
if (this.rsServices == null) { //rsServices为HRegionServer提供的服务类
return;
}
synchronized (writestate) { //检查状态是为了避免重复请求
if (this.writestate.isFlushRequested()) {
return;
}
writestate.flushRequested = true; //更新writestate的状态
}
// Make request outside of synchronize block; HBASE-818.
this.rsServices.getFlushRequester().requestFlush(this, false);
if (LOG.isDebugEnabled()) {
LOG.debug("Flush requested on " + this);
}
}
关键的是下面一句:
this.rsServices.getFlushRequester().requestFlush(this, false);
其中rsServices向RegionServer发起一个RPC请求,getFlushRequester()是RegionServer中的成员变量coreFlusher中定义的方法,该变量是MemStoreFlusher类型,用于管理该RegionServer上的各种flush请求,它里面定义的几个关键变量如下:
private final BlockingQueue<FlushQueueEntry> flushQueue =
new DelayQueue<FlushQueueEntry>(); //BlockingQueue阻塞队列 DelayQueue使用优先级队列实现的无界阻塞队列
private final Map<Region, FlushRegionEntry> regionsInQueue =
new HashMap<Region, FlushRegionEntry>();
private AtomicBoolean wakeupPendin