HBase源码分析之HRegionServer上MemStore的flush处理流程(一)

本文深入剖析了HBase HRegionServer如何处理MemStore的flush请求,主要关注cacheFlusher的初始化、flush请求的处理流程,以及FlushHandler线程的角色。文章详细解释了flushQueue、regionsInQueue、FlushRegionEntry和WakeupFlushThread的工作原理,揭示了HBase如何通过DelayQueue管理flush请求,并防止内存压力导致的异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在《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);
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值