概述

提升数据库读取性能的一个核心方法是,尽可能将热点数据存储到内存中,以避免昂贵的IO开销;为了提升读取性能,HBase也实现了一种读缓存结构——BlockCache。客户端读取某个Block,首先会检查该Block是否存在于Block Cache,如果存在就直接加载出来,如果不存在则去HFile文件中加载,加载出来之后放到Block Cache中,后续同一请求或者邻近数据查找请求可以直接从内存中获取,以避免昂贵的IO操作,BlockCache是RegionServer级别的,一个RegionServer只有一个BlockCache

LRUBlockCache

LRUBlockCache实现相对比较简单。使用一个ConcurrentHashMap管理BlockKey到Block的映射关系,缓存Block只需要将BlockKey和对应的Block放入该HashMap中,查询缓存就根据BlockKey从HashMap中获取即可

1.缓存分层策略

HBase采用了缓存分层设计,将整个BlockCache分为三个部分:single-access、multi-access和in-memory

  • Single:一个Block从HDFS中加载出来之后首先放入single-access区
  • Mutile:多次请求访问到一个Block,就会将这个Block移从Single到multi-access区
  • In-Memory:对列族属性中的 IN_MEMEORY 设置为 true,这个级别的数据块是最后才会被挤出去,Catalog 表是默认启动了 IN_MEMORY 表的特性;

2.LRU淘汰算法实现

每次cache block时,系统将BlockKey和Block放入HashMap后都会检查BlockCache总量是否达到阈值,如果达到阈值,就会唤醒淘汰线程对Map中的Block进行淘汰。

系统设置三个MinMaxPriorityQueue队列,分别对应上述三个分层,每个队列中的元素按照最近最少被使用排列,系统会优先poll出最近最少使用的元素,将其对应的内存释放。
可见,三个分层中的Block会分别执行LRU淘汰算法进行淘汰。

3.LRU方案优缺点

LRU方案使用JVM提供的HashMap管理缓存,简单有效。
但随着数据从single-access区晋升到mutil-access区,基本就伴随着对应的内存对象从young区到old区 ,
晋升到old区的Block被淘汰后会变为内存垃圾,最终由CMS回收掉(Conccurent Mark Sweep,一种标记清除算法),
然而这种算法会带来大量的内存碎片,碎片空间一直累计就会产生臭名昭著的Full GC。

SlabCache

为了解决LRUBlockCache 内存问题,BucketCache方案横空出世;BucketCache默认有三种工作模式:heap、offheap 和 file;

  • heap模式表示这些Bucket是从JVM Heap中申请的;
  • offheap模式使用DirectByteBuffer技术实现堆外内存存储管理;
  • file模式使用类似SSD的存储介质来缓存Data Block

内存分配时,相比offheap直接从操作系统分配内存,heap模式需要首先从操作系统分配内存再拷贝到JVM heap,因此更耗时;但是反过来,读取缓存时heap模式可以从JVM heap中直接读取,而offheap模式则需要首先从操作系统拷贝到JVM heap再读取,因此更费时。

posted on 2025-09-16 23:56  饺子挺好的  阅读(15)  评论(0)    收藏  举报