hbase BlockCache及3种实现方案详解

       

目录

       LRUBlockCache

          LRUBlockCache缓存分层策略

          LRUBlockCache优缺点

      SlabCache

       BucketCache

  BucketCache中Blcok缓存写入,读取


继上篇说到hbase读性能优化的一个重要手段。就是BlockCache..客户端读取某个Block,首先会检查该Block是否存在于Block Cache,如果存在就直接加载出来,如果不存在则去Hfile文件中加载,加载出来之后放到BlockCache中。后续同一请求或者邻近数据查找请求可以直接去内存中获取,以避免昂贵的IO操作。

        BlockCache主要用来缓存Block.需要关注的是,Block是Hbase中最小的数据读取单元。

        BlockCache本质使用的是一个ConcurrentHashMap来管理BlockKey到Block的映射关系。

        BlockCache是regionServer级别的。一个RegionServer只有一个BlockCache.在Region启动的时候完成BlockCache的初始化工作。到现在为止,针对BlockCache有3种实现方案。

  1.         LRUBlockCache是最早的实现方案,也是默认的实现方案。
  2.         SlabCache.在hbase0.98版本之后,已经不建议使用该方案。
  3.         BucketCache  基于SlabCache设计的一种高效缓存方案。

        接下来讲解具体3种实现方案。

       LRUBlockCache

        使用一个ConcurrentHashMap来管理BlockKey和Block的映射关系。缓存Block只需要将BlockKey和对应的Block放入到HashMap种。查询缓存就根据BlockKey从hashmap种获取即可。同时,该方案采用严格的LRU淘汰算法,当BlockCache总量达到一定阈值之后就会启动淘汰机制,最近最少使用的Block会被置换出来。

          LRUBlockCache缓存分层策略

         Hbase将整个BlockCache分为3个部分:single-access,multi-access,in-memory.分别占用整个cache的25%,50%,25%。          在一次随机读中,一个Block从hdfs加载出来之后首先会放入single-access区,后续如果有多次请求访问到这个Block,就会将Block移到multi-access区,而in-memory区表示数据可以常驻内存(可以通过建表的时候设置列簇属性IN_MEMORY=true,设置之后该列簇的Block从磁盘加载出来之后会直接放入到in-memory区),一般用来存放访问频繁,量小的数据,比如元数据。其实,hbase:meta,hbase:namespace等都存放在in-memory区。

         特别注意,3层都会经过LRU淘汰算法进行淘汰不常用的数据。在每次cache Block时,系统将BlockKey和Block放入HashMap后会检查BlockCache总量是否达到阈值,如果达到阈值,就会唤醒淘汰线程对Map中的Block进行淘汰。系统设置3个MinMaxPriorityQueue,分别对应3个分层,每个队列中的元素按照最近最少使用的规则排序,系统会优先取出最近最少使用的Block,将其对应的内存释放。

          LRUBlockCache优缺点

          随着数据从single-access区晋升到multi-access区或者长时间停留在single-access区,对应的内存对象会从young区晋升到old区,晋升到old区的Block被淘汰后变为内存垃圾,最终由CMS回收。显然这种算法会带来大量的内存碎片,甚至碎片化越老越严重的情况下,CMS会使用Serialold来清理老年代也就是单线程并且会有stw.

      SlabCache

          slabCache实现了堆外内存存储,不再由JVM来管理数据内存。默认情况下,会在初始化的时候在堆外分配两个缓冲区,分别占BlockCache的80%和20%。 80%区用来存储小于等于64K的Block.20%用来保存小于等于128K的Block,当然如果Block大于128K,那么就和LRUBlockCache相同了。因为不同表不同列簇设置的BlockSize可能都不相同,所以对于存储大于128K的Block该方案就不能达到缓存block的目的。还有就是因为SlabCache中固定大小内存设置,会导致内存使用率的降低。

       BucketCache

         bucketCache通过不同配置方式可以有三种模式,

  1.  heap 表示bucket是从JVM Heap中申请的
  2. offheap 表示使用堆外内存存储管理。
  3. file  使用磁盘来存储缓存DataBlock.     

         无论哪一种模式,bucketCache都会申请许多带有固定大小标签的Bucket.和slabCache一样,每一种bucket存储一种指定BlockSize的DataBlock.但是不同的是,BucketCache会在初始化的时候申请14种不同大小的Bucket。而且每个Bucket的空间可以动态增加。

          默认每个bucket的大小为2M.

          hbase启动时会默认决定标签的分类:4K,8K,16K,48K,64K,96K........512K. 最后剩余的Bucket都分配到最大的标签,默认512K.

          hbase使用BucketAllocator类实现对Bucket的组织管理。

          针对相同类型的标签,都由一个BucketSizeInfo来进行管理。

     

  BucketCache中Blcok缓存写入,读取

  

          针对block写入bucketCache流程:

          hbase在BucketCache中设置了多个RAMCache.系统首先会根据BlockKey进行hash,根据hash结果将Block分配到对应的RAMCache中。

          WriteThread是异步线程,一个RAMCache对应一个WriteThread, 负责将RAMCache中取出所有的Block,然后BucketAllocator会对这些block分配内存空间,选择对应大小的bucket进行存放,返回对应的物理地址偏移量。

   然后writeThread将分配好的B和对应分配好的物理地址偏移量通过IOEngine模块执行具体的内存写入。写入到BackingMap中。

   针对bucketCache读取流程:

   首先从RAMCache中查找,对于没来得及写入到bucket的block,一定存储在RAMCache中。

   如果没找到再根据blockkey在BackingMap中查找对应的物理地址偏移量。

   根据物理地址偏移量直接从内存中查找对应的Block数据。

猜你喜欢

转载自blog.csdn.net/weixin_40954192/article/details/106963979
今日推荐