HBase源码分析之BlockCache一:综述及LruBlockCache的实现

BlockCache综述

读取数据时,如果每次都是访问hfile,这样其性能是很低的,特别是在随机小数据量读的场景下。为提高IO性能,hbase提供了缓存的机制BlockCache。根据帕列托法则(二八法则),我们并不需要将所有数据都进行缓存,能保证热点数据(20%)缓存起来即可。这样就可以大大提高读取的效率。
BlockCache是RegionServer级别的,即每个RegionServer会有一个BlockCache,BlockCache会将要读取的block放到内存中,以便后续的访问。HBase提供了4种BlockCache的方案

  1. 最初的LruBlockCache
  2. SlabCache,见HBASE-4027,0.92版本提供
  3. BucketCache,见HBASE-7404,0.95版本
  4. ExternalBlockCache,见HBASE-13170,1.10版本

其中SlabCache由于以下原因,在1.0版本后被废弃了HBASE-11307

  1. 使用了单一cache大小,由于有多种类型的blocksize这样会导致内存使用率低,特别是在使用了DataBlockEncoding的情况下。
  2. 使用了DoubleBlockCache,block会在SlabCache和LRUBlockCache都缓存一份,当在SlabCache中命中block时会把block放到LRUBlockCache中,这样会导致CMS GC和造成堆碎片。比单独用LRUBlockCache没有改善。
  3. 堆外内存的性能没有堆内存高

LruBlockCache
LruBLockCache是在JVM的heap中的,其中的block有3个级别的优先级分别为single-access, multiple-accesses, and in-memory,这里使用多种策略可以避免由于有大批量的scan操作时,导致缓存全部被替换的问题。这3种策略默认占空间比例为0.25、0.5、0.25.如果表的family中有定义IN_MEMORY=true则该family下的块会设置为in-memory,一般访问特别频繁的数据可以这样设置,如base:meta表.而其他的block首次访问的时候为single-access。后续如果再次访问在cache中的这个block就会改为multiple-accesses。如果这些块的大小超过了上线,就会触发回收处理,使用的是LRU(Least-Recently-Used)算法。如果只使用LruBlockCache,在内存较大时会存在GC的问题导致服务中断。

BucketCache
BucketCache解决了SlabCache中存在的问题,首先其支持多种Cache方式,有heap、offheap和file。

  1. heap为使用jvm中的heap
  2. offheap为使用堆外内存
  3. file为使用文件的方式,如虚拟内存文件系统tmpfs或者高速SSD盘

另外支持多种不同大小的bucket,以适应不同大小的blocksize。可以通过参数hbase.bucketcache.bucket.sizes来配置不同bucket的大小。默认有14种大小从5k~513k。而使用堆外内存的性能问题在新版本中解决HBASE-11425

ExternalBlockCache
ExternalBlockCache为使用外部的其他缓存服务来提供,如memcached和redis等。这个可以避免在服务器挂掉或者升级的时候缓存全部失效的问题。

在使用方式上可以单独使用LRUBlockCache,或者组合起来使用,多级缓存的方式。LruBlockCache为一级缓存,BucketCache或者ExternalBlockCache为二级缓存。
见如下代码:

// CacheConfig.java
public static synchronized BlockCache instantiateBlockCache(Configuration conf) {
    if (GLOBAL_BLOCK_CACHE_INSTANCE != null) return GLOBAL_BLOCK_CACHE_INSTANCE;
    if (blockCacheDisabled) return null;
    MemoryUsage mu = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
    LruBlockCache l1 = getL1(conf, mu);
    // blockCacheDisabled is set as a side-effect of getL1(), so check it again after the call.
    if (blockCacheDisabled) return null;
    BlockCache l2 = getL2(conf, mu);
    if (l2 == null) {
      GLOBAL_BLOCK_CACHE_INSTANCE = l1;
    } else {
      boolean useExternal = conf.getBoolean(EXTERNAL_BLOCKCACHE_KEY, E
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值