在《HBase源码分析之HRegion上MemStore的flsuh流程(一)》、《HBase源码分析之HRegion上MemStore的flsuh流程(二)》等文中,我们介绍了HRegion上Memstore flush的主体流程和主要细节。但是,HRegion只是HBase表中按照行的方向对一片连续的数据区域的抽象,它并不能对外提供单独的服务,供客户端或者HBase其它实体调用。而HRegion上MemStore的flush还是要通过HRegionServer来对外提供服务的。下面,我们就详细探究下HRegionServer上是如何实现这点的。
在HRegionServer中,有一个叫做cacheFlusher的东东,它是什么呢?我们先看一下它是如何被定义的:
// Cache flushing
// memstore内存刷新管理对象
protected MemStoreFlusher cacheFlusher;
可以发现,cacheFlusher是MemStoreFlusher类型的一个对象,我们来看下类的注释及定义:
/**
* Thread that flushes cache on request
* 处理刷新缓存请求的线程
*
* NOTE: This class extends Thread rather than Chore because the sleep time
* can be interrupted when there is something to do, rather than the Chore
* sleep time which is invariant.
*
* @see FlushRequester
*/
@InterfaceAudience.Private
class MemStoreFlusher implements FlushRequester {
cacheFlusher实际上就是HRegionServer上处理刷新缓存请求的线程。那么接下来的问题就是,cacheFlusher是如何被初始化的?它又是如何处理flush请求的?带着这两个问题,我们继续本文。
一、如何初始化cacheFlusher
首先,我们发现HRegionServer继承自HasThread,而HasThread实现了Runnable接口,那么在其内部肯定会执行run()方法,而run()方法的开始,有如下代码:
try {
// Do pre-registration initializations; zookeeper, lease threads, etc.
preRegistrationInitialization();
} catch (Throwable e) {
abort("Fatal exception during initialization", e);
}
继续追踪preRegistrationInitialization()方法,在其内部,调用了initializeThreads()方法,如下:
if (!isStopped() && !isAborted()) {
initializeThreads();
}
而这个initializeThreads()方法,做的主要工作就是初始化HRegionServer内部的各种工作线程,其中就包括cacheFlusher,代码如下:
// Cache flushing thread.
// 缓存刷新线程
this.cacheFlusher = new MemStoreFlusher(conf, this);
接下来,我们在看看这个MemStoreFlusher类是如何定义及工作的。首先看下它最主要的几个成员变量:
首当其冲的便是flushQueue,其定义如下:
private final BlockingQueue<FlushQueueEntry> flushQueue =
new DelayQueue<FlushQueueEntry>();
flushQueue是MemStoreFlusher中非常重要的一个变量,它是一个存储了Region刷新缓存请求的队列。而与flushQueue同时被更新的是regionsInQueue,它存储的是HRegion到FlushRegionEntry映射关系的集合,FlushRegionEntry是对发起memstore刷新请求的HRegion的一个封装,不仅包含了HRegion实例,还包括HRegion刷新memstore请求的产生时间,到期时间,以及一种类似续约的处理方式,即延长该请求的到期时间等。regionsInQueue的定义如下:
private final Map<HRegion, FlushRegionEntry> regionsInQueue =
new HashMap<HRegion, FlushRegionEntry>();
flushQueue和regionsInQueue的更新是同步的,即如果在flushQueue中加入或删除一条记录,那么在regionsInQueue中也会同步加入或删除一条记录。
接下来比较重要的便是flushHandlers,它是FlushHandler类型的一个数组,定义如下:
private final FlushHandler[] flushHandlers;
FlushHandler是什么呢?它是处理缓存刷新的线程类,线程一旦启动后,在其run()方法内,就会不停的从flushQueue队列中拉取flush请求进行处理,其类的定义如下:
/**
* 处理缓存刷新的线程类
*/
private class FlushHandler extends HasThread {
以上就是MemStoreFlusher内执行flush流程最重要的几个成员变量,其他的变量都是一些辅助性的,这里不再做详细介绍。
下面,我们来看下MemStoreFlusher的构造及成员变量的初始化,构造函数如下:
/**
* @param conf
* @param server
*/
public MemStoreFlusher(final Configuration conf,
final HRegionServer server) {
super();
// 赋值RegionServer实例server
this.server = server;
// 线程唤醒频率threadWakeFrequency,取参数hbase.server.thread.wakefrequency配置的值,默认为10s,即线程的工作频率
this.threadWakeFrequency =
conf.getLong(HConstants.THREAD_WAKE_FREQUENCY, 10 * 1000);
// 获取最大可用堆内存max
long max = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax();
// 获取全局memstore所占堆内存的百分比globalMemStorePercent
float globalMemStorePercent = HeapMemorySizeUtil.getGlobalMemStorePercent(conf, true);