`
brianf
  • 浏览: 37093 次
  • 来自: 杭州
社区版块
存档分类
最新评论

HBase BlockCache 代码分析

阅读更多
1. Cache 读写
调用逻辑:
hmaster.handleCreateTable->HRegion.createHRegion-> HRegion. initialize->initializeRegionInternals->instantiateHStore
->Store.Store->new CacheConfig(conf, family)-> CacheConfig.instantiateBlockCache->new LruBlockCache
传入参数

  /**
   * Configurable constructor.  Use this constructor if not using defaults.
   * @param maxSize maximum size of this cache, in bytes
   * @param blockSize expected average size of blocks, in bytes
   * @param evictionThread whether to run evictions in a bg thread or not
   * @param mapInitialSize initial size of backing ConcurrentHashMap
   * @param mapLoadFactor initial load factor of backing ConcurrentHashMap
   * @param mapConcurrencyLevel initial concurrency factor for backing CHM
   * @param minFactor percentage of total size that eviction will evict until
   * @param acceptableFactor percentage of total size that triggers eviction
   * @param singleFactor percentage of total size for single-access blocks
   * @param multiFactor percentage of total size for multiple-access blocks
   * @param memoryFactor percentage of total size for in-memory blocks
   */
  public LruBlockCache(long maxSize, long blockSize, boolean evictionThread,
      int mapInitialSize, float mapLoadFactor, int mapConcurrencyLevel,
      float minFactor, float acceptableFactor,
      float singleFactor, float multiFactor, float memoryFactor) 

new LruBlockCache时除了设置默认的参数外,还会创建evictionThread并wait和一个定时打印的线程StatisticsThread


当执行HFileReaderV2的readBlock时,会先看判断是否开户了Cache ,如果开启,则使用cache中block

        // Check cache for block. If found return.
        if (cacheConf.isBlockCacheEnabled()) {
          // Try and get the block from the block cache.  If the useLock variable is true then this
          // is the second time through the loop and it should not be counted as a block cache miss.
          HFileBlock cachedBlock = (HFileBlock)
              cacheConf.getBlockCache().getBlock(cacheKey, cacheBlock, useLock);
          if (cachedBlock != null) {
            BlockCategory blockCategory =
                cachedBlock.getBlockType().getCategory();

            getSchemaMetrics().updateOnCacheHit(blockCategory, isCompaction);

            if (cachedBlock.getBlockType() == BlockType.DATA) {
              HFile.dataBlockReadCnt.incrementAndGet();
            }

            validateBlockType(cachedBlock, expectedBlockType);

            // Validate encoding type for encoded blocks. We include encoding
            // type in the cache key, and we expect it to match on a cache hit.
            if (cachedBlock.getBlockType() == BlockType.ENCODED_DATA &&
                cachedBlock.getDataBlockEncoding() !=
                    dataBlockEncoder.getEncodingInCache()) {
              throw new IOException("Cached block under key " + cacheKey + " " +
                  "has wrong encoding: " + cachedBlock.getDataBlockEncoding() +
                  " (expected: " + dataBlockEncoder.getEncodingInCache() + ")");
            }
            return cachedBlock;
          }
          // Carry on, please load.
        }
在getBlock方法中,会更新一些统计数据,重要的时更新
BlockPriority.SINGLE为BlockPriority.MULTI
  public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching, boolean repeat) {
    CachedBlock cb = map.get(cacheKey);
    if(cb == null) {
      if (!repeat) stats.miss(caching);
      return null;
    }
    stats.hit(caching);
    cb.access(count.incrementAndGet());
    return cb.getBuffer();
  }
---------------------
若是第一次读,则将block加入Cache.

        // Cache the block if necessary
        if (cacheBlock && cacheConf.shouldCacheBlockOnRead(
            hfileBlock.getBlockType().getCategory())) {
          cacheConf.getBlockCache().cacheBlock(cacheKey, hfileBlock,
              cacheConf.isInMemory());
        }

2. LRU evict

写入cache时就是将block加入到 一个 ConcurrentHashMap中,并更新Metrics,之后判断if(newSize > acceptableSize() && !evictionInProgress), acceptableSize是初始化时给的值(long)Math.floor(this.maxSize * this.acceptableFactor),acceptableFactor是一个百分比,是可以配置的:"hbase.lru.blockcache.acceptable.factor"(0.85f), 这里的意思就是判断总Size是不是大于这个值,如果大于并且没有正在执行的eviction线程, 那么就执行evict。

/**
   * Cache the block with the specified name and buffer.
   * <p>
   * It is assumed this will NEVER be called on an already cached block.  If
   * that is done, an exception will be thrown.
   * @param cacheKey block's cache key
   * @param buf block buffer
   * @param inMemory if block is in-memory
   */
  public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory) {
    CachedBlock cb = map.get(cacheKey);
    if(cb != null) {
      throw new RuntimeException("Cached an already cached block");
    }
    cb = new CachedBlock(cacheKey, buf, count.incrementAndGet(), inMemory);
    long newSize = updateSizeMetrics(cb, false);
    map.put(cacheKey, cb);
    elements.incrementAndGet();
    if(newSize > acceptableSize() && !evictionInProgress) {
      runEviction();
    }
  }

在evict方法中,
1. 计算总size和需要free的size, minsize = (long)Math.floor(this.maxSize * this.minFactor);其中minFactor是可配置的"hbase.lru.blockcache.min.factor"(0.75f);
      long currentSize = this.size.get();
      long bytesToFree = currentSize - minSize();

2. 初始化三种BlockBucket:bucketSingle,bucketMulti,bucketMemory并遍历map,按照三种类型分别add进各自的queue(MinMaxPriorityQueue.expectedSize(initialSize).create();)中, 并按照访问的次数逆序。
三种类型的区别是:
    SINGLE对应第一次读的
    MULTI对应多次读
    MEMORY是设定column family中的IN_MEMORY为true的

      // Instantiate priority buckets
      BlockBucket bucketSingle = new BlockBucket(bytesToFree, blockSize,
          singleSize());
      BlockBucket bucketMulti = new BlockBucket(bytesToFree, blockSize,
          multiSize());
      BlockBucket bucketMemory = new BlockBucket(bytesToFree, blockSize,
          memorySize());


其中三种BlockBuckt Size大小分配比例默认是:
  static final float DEFAULT_SINGLE_FACTOR = 0.25f;
  static final float DEFAULT_MULTI_FACTOR = 0.50f;
  static final float DEFAULT_MEMORY_FACTOR = 0.25f;

  private long singleSize() {
    return (long)Math.floor(this.maxSize * this.singleFactor * this.minFactor);
  }
  private long multiSize() {
    return (long)Math.floor(this.maxSize * this.multiFactor * this.minFactor);
  }
  private long memorySize() {
    return (long)Math.floor(this.maxSize * this.memoryFactor * this.minFactor);
  }


并将三种BlockBuckt 加入到优先队列中,按照totalSize - bucketSize排序,,再计算需要free大小,执行free:
PriorityQueue<BlockBucket> bucketQueue =
        new PriorityQueue<BlockBucket>(3);

      bucketQueue.add(bucketSingle);
      bucketQueue.add(bucketMulti);
      bucketQueue.add(bucketMemory);

      int remainingBuckets = 3;
      long bytesFreed = 0;

      BlockBucket bucket;
      while((bucket = bucketQueue.poll()) != null) {
        long overflow = bucket.overflow();
        if(overflow > 0) {
          long bucketBytesToFree = Math.min(overflow,
            (bytesToFree - bytesFreed) / remainingBuckets);
          bytesFreed += bucket.free(bucketBytesToFree);
        }
        remainingBuckets--;
      }

free方法中一个一个取出queue中block,由于是按照访问次数逆序,所以从后面取出就是先取出访问次数少的,将其在map中一个一个remove, 并更新Mertrics.

    public long free(long toFree) {
      CachedBlock cb;
      long freedBytes = 0;
      while ((cb = queue.pollLast()) != null) {
        freedBytes += evictBlock(cb);
        if (freedBytes >= toFree) {
          return freedBytes;
        }
      }
      return freedBytes;
    }




  protected long evictBlock(CachedBlock block) {
    map.remove(block.getCacheKey());
    updateSizeMetrics(block, true);
    elements.decrementAndGet();
    stats.evicted();
    return block.heapSize();
  }

3. HBase LruBlockCache的特点是针对不同的访问次数使用不同的策略,避免频繁的更新的Cache(便如Scan),这样更加有利于提高读的性能。


分享到:
评论

相关推荐

    hbase权威指南源码

    源码分析: 1. **目录结构**: 解压后的`hbase-book-master`包含项目的基本目录结构,如`src/main/java`用于存放Java源代码,`src/main/resources`存储资源配置文件,`pom.xml`是Maven项目对象模型,定义了项目的...

    HBase源代码 hbase-0.98.23

    例如,`org.apache.hadoop.hbase.regionserver.HStore`类实现了MemStore和BlockCache,它们分别缓存内存中的新写入数据和硬盘上的热数据,提高读写效率。同时,HBase还支持Compaction操作,通过`org.apache.hadoop....

    HBase实战源码

    源码分析是理解HBase工作原理和技术细节的重要途径。HBase在大数据领域扮演着关键角色,它能够处理海量数据并提供实时访问。下面,我们将深入探讨HBase的核心概念和源码中的关键组件。 1. **HBase架构**:HBase基于...

    hbase 源码包

    HBase 0.94.4的源码分析有助于我们深入了解其内部机制,从而更好地进行系统设计和优化。无论是对于开发者还是管理员,掌握HBase的核心原理都将极大地提升在大数据领域的实践能力。通过不断学习和实践,我们可以更好...

    hbase 1.2.0源码

    HBase 1.2.0是该数据库的一个稳定版本,包含了众多优化和改进,对于想要深入理解HBase工作原理或者进行大数据分析的学习者来说,研究其源码是非常有价值的。 一、HBase架构与核心概念 1. 表与Region:HBase中的...

    Hbase权威指南随书源代码源码包

    通过研究这些源码,读者可以了解到HBase的内部工作原理,如MemStore、HLog、BlockCache等关键组件的作用,以及它们如何协同工作以实现高效的数据存储和检索。此外,还能学习到如何根据业务需求来设计合理的表结构,...

    hbase 数据库

    11. **优化策略**:包括合理设置Region大小、预分区表、选择合适的Column Family、启用BlockCache等,以提升HBase的性能。 12. **安全配置**:在生产环境中,可能需要配置HBase与Kerberos进行集成,以实现身份验证...

    hbase-1.2.6-bin+src.tar.rar

    根据业务需求调整HBase配置,如Region大小、Compaction策略、BlockCache设置等,提升系统性能。 五、学习资源 参考链接:[博客教程](https://blog.csdn.net/haobindayi/article/details/82948123),该博客提供了...

    HBaseTest_hbase_源码

    "HBaseTest"的源码中可能包含对预读取(BlockCache)、压缩、过滤器等优化手段的使用,这些都对提升HBase的性能至关重要。 通过分析"HBaseTest"源码,我们可以更直观地理解HBase的工作原理和使用方式,为实际项目...

    hbase1.0.3_part1

    3. **实时查询**:HBase支持实时读写操作,通过内存缓存和BlockCache机制,提供了亚秒级的查询响应速度。 4. **稀疏性**:HBase可以存储大量的稀疏数据,即许多行或列可能存在大量缺失值,只存储有实际数据的位置,...

    《Hbase权威指南》原版

    - **缓存机制**:HBase利用内存缓存来加速读取操作,包括MemStore(内存中存储未刷新到磁盘的数据)和BlockCache(缓存经常访问的数据块)。 #### 四、HBase的应用场景 - **实时数据分析**:由于HBase提供了低延迟...

    hbase-2.0.0.3.0.0.0-1634-bin.tar.gz

    3. 性能调优:通过调整HBase的配置参数,如MemStore大小、BlockCache设置等,可以优化读写性能。 4. 监控与故障排查:Ambari提供了丰富的监控工具,包括HBase的CPU使用、磁盘I/O、网络流量等关键指标,帮助你及时...

    hbase1.2+java开发最小依赖jar包合集

    8. **性能优化**:在开发过程中,了解和利用HBase的预读取(BlockCache)、MemStore和Compaction等特性可以显著提升性能。 9. **异常处理**:Java开发时,需要处理HBase特有的异常,如`IOException`、`...

    hbase-2.2.6-bin.tar.zip

    在性能优化方面,可以通过调整Region大小、预分区表、使用BlockCache和MemStore来提升读写性能。HBase还支持 Coprocessors,这是一种在Region Server端运行的插件机制,可以用于实现自定义的业务逻辑,比如数据过滤...

    hbase-2.2.6:hbase社区版源码2.2.6

    HBase性能优化包括Region大小调整、BlockCache配置、Compaction策略优化、WAL(Write-Ahead Log)管理等。通过对这些参数的调整,可以显著提高读写性能和系统稳定性。 总之,HBase 2.2.6的源码提供了深入理解...

    hbase-0.94.5-security.tar.gz

    9. **查询优化**:虽然HBase主要面向随机读写,但通过预读(BlockCache)和Bloom Filter等机制,可以优化查询性能,减少磁盘I/O。 10. **监控与管理**:HBase提供了一套监控和管理工具,包括JMX、Web UI和命令行...

    HBase_官方文档-中文翻译

    监控是运维的关键部分,HBase 提供了丰富的 Metrics,如 RegionServer 的 BlockCache 统计、读写延迟、内存使用情况等,这些指标有助于诊断和优化集群性能。 总结来说,HBase 是一个强大的大数据存储解决方案,尤其...

    大数据系列-Hbase

    - **BlockCache**: 缓存机制,提高读取性能。 - **Replication**: 数据冗余,提供容错和高可用性。 - ** Coprocessors**: 在Region Server上运行的用户自定义代码,可以扩展HBase的功能。 ### 7. 文件名称解析 ...

    No.1HBase3.0张铎.zip

    - 性能优化:如改进的BlockCache机制,提升了读取性能;优化了写入流程,降低了延迟。 - 功能扩展:支持更多的过滤器和索引,便于复杂查询操作。 - 安全性提升:增强了用户认证和授权机制,提供了更完善的安全...

Global site tag (gtag.js) - Google Analytics