HBase 源码学习 ---- Flush (3)

本文深入探讨HBase的StoreFlusher,重点关注flush操作,包括DefaultStoreFlusher和StripStoreFlusher的实现。分析了flushCache()方法、CreateScanner()和performFlush()方法的工作原理,并提及了strip compaction的实验特性。

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

上一篇主要梳理了Flush的大致流程,包括prepare,flush,commit三个阶段,其中最耗时,涉及磁盘IO的阶段是将memstore的快照写入临时文件的flush阶段,这篇深入flush阶段进行梳理。
Store通过调用flushCache() 方法,将快照写入临时文件,实际是调用storeEngine中,StoreFlusher的flushSnapshot方法:

StoreFlusher flusher = storeEngine.getStoreFlusher();
    IOException lastException = null;
    for (int i = 0; i < flushRetriesNumber; i++) {
      try {
        List<Path> pathNames =
            flusher.flushSnapshot(snapshot, logCacheFlushId, status, throughputController);

StoreFlusher是一个抽象类,目前HBase有两种实现,一种是DefaultStoreFlusher, 一种是StripeStoreFlusher。

StoreFlusher

StoreFlusher 包含3个非抽象方法finalizeWriter(), createScanner(), performFlush() 和一个抽象方法flushSnapshot()。

CreateScanner() 方法
protected InternalScanner createScanner(KeyValueScanner snapshotScanner,
      long smallestReadPoint) throws IOException {
    InternalScanner scanner = null;
    if (store.getCoprocessorHost() != null) {
      scanner = store.getCoprocessorHost().preFlushScannerOpen(store, snapshotScanner,
          smallestReadPoint);
    }
    if (scanner == null) {
      Scan scan = new Scan();
      scan.setMaxVersions(store.getScanInfo().getMaxVersions());
      scanner = new StoreScanner(store, store.getScanInfo(), scan,
          Collections.singletonList(snapshotScanner), ScanType.COMPACT_RETAIN_DELETES,
          smallestReadPoint, HConstants.OLDEST_TIMESTAMP);
    }
    assert scanner != null;
    if (store.getCoprocessorHost() != null) {
      try {
        return store.getCoprocessorHost().preFlush(store, scanner);
      } catch (IOException ioe) {
        scanner.close();
        throw ioe;
      }
    }
    return scanner;
  }

创建一个scanner用来扫描snapshot,由于仅扫描内存,所以scan速度会比较快,如果有coprocessor,会执行其preFlush方法。

performFlush() 方法
protected void performFlush(InternalScanner scanner, Compactor.CellSink sink,
      long smallestReadPoint, ThroughputController throughputController) throws IOException {
	int compactionKVMax =
      	conf.getInt(HConstants.COMPACTION_KV_MAX, HConstants.COMPACTION_KV_MAX_DEFAULT);

    ScannerContext scannerContext =
        ScannerContext.newBuilder().setBatchLimit(compactionKVMax).build();

    List<Cell> kvs = new ArrayList<Cell>();
    boolean hasMore;
    String flushName = ThroughputControlUtil.getNameForThrottling(store, "flush");
    boolean control = throughputController != null && !store.getRegionInfo().isSystemTable();
    if (control) {
      throughputController.start(flushName);
    }
    try {
      do {
        hasMore = scanner.next(kvs, scannerContext);
        if (!kvs.isEmpty()) {
          for (Cell c : kvs) {
            sink.append(c);
            int len = KeyValueUtil.length(c);
            if (control) {
              throughputController.control(flushName, len);
            }
          }
          kvs.clear();
        }
      } while (hasMore);
    } catch (InterruptedException e) {
      throw new InterruptedIOException("Interrupted while control throughput of flushing "
          + flushName);
    } finally {
      if (control) {
        throughputController.finish(flushName);
      }
    }
  }

一开始获取超参"hbase.hstore.compaction.kv.max",限制scanner一个batch包含的最多KV数量,默认是10。
finalizeWriter() 方法将对应hfile的log 序号写入metadata中。

DefaultStoreFlusher

DefaultStoreFlusher中,flushSnapshot方法逻辑很简单,首先创建memstore的scanner,再创建一个StoreFile.Writer进行写入,最后调用finalizeWriter方法。

StripStoreFlusher

对应于底层StoreFile使用了StripCompaction的情况,从HBase官方文档,该特性还处于实验阶段,详解介绍参考HBase官网文档:
https://hbase.apache.org/book.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值