上图为BucketCache的内存组织形式,图中上半部分是逻辑组织结构,下半部分是对应的物理组织结构。HBase启动之后会在内存中申请大量的Bucket,每个 Bucket的大小默认为2MB。
每个 Bucket 会有一个baseoffset变量和一个size标签,其中 baseoffset变量表示这个Bucket在实际物理空间中的起始地址,因此Block 的物理地址就可以通过baseoffset和该Block在 Bucket的偏移量唯一确定;size标签表示这个Bucket可以存放的Block大小,比如图中左侧Bucket的size标签为65KB,表示可以存放64KB的Block,右侧Bucket的 size标签为129KB,表示可以存放128KB的 Block。
bucket的组织管理
HBase中使用BucketAllocator类实现对 Bucket的组织管理。
1)HBase会根据每个Bucket的 size标签对Bucket进行分类,相同size标签的Bucket由同一个 BucketSizeInfo管理,如图所示,左侧存放64KB Block 的 Bucket由 65KBBucketSizeInfo管理,右侧存放128KB Block 的Bucket由 129KB BucketSizeInfo管理。可见,BucketSize大小总会比 Block本身大1KB,这是因为Block本身并不是严格固定大小的,总会大那么一点,比如64K的 Block总是会比64K大一些。
图中实线表示Block 写入流程,虚线表示 Block缓存读取流程。
1)将Block 写入RAMCache。实际实现中,HBase,设置了多个RAMCache,系统首先会根据blockKey进行hash,根据hash结果将Block分配到对应的RAMCache中。
2 ) WriteThead 从 RAMCache中取出所有的Block。和RAMCache相同,HBase 会同时启动多个 WriteThead并发地执行异步写入,每个 WriteThead对应一个RAMCache。
3)每个 WriteThead会遍历RAMCache中所有Block,分别调用bucketAllocator为这些Block分配内存空间。
4 ) BucketAllocator 会选择与Block大小对应的 Bucket进行存放,并且返回对应的物理地址偏移量offset。
5 ) WriteThead将 Block以及分配好的物理地址偏移量传给IOEngine模块,执行具体的内存写入操作。
6)写入成功后,将blockKey与对应物理内存偏移量的映射关系写入BackingMap中,方便后续查找时根据blockKey直接定位。
1)首先从RAMCache中查找。对于还没有来得及写入Bucket的缓存Block,一定存储在RAMCache 中。
2)如果在RAMCache中没有找到,再根据blockKey在 BackingMap中找到对应的物理偏移地址量offset。
3)根据物理偏移地址offset直接从内存中查找对应的 Block数据。
BucketCache默认有三种工作模式: heap、offheap和 file。这三种工作模式在内存逻辑组织形式以及缓存流程上都是相同的;但是三者对应的最终存储介质有所不同,即上述所讲的IOEngine有所不同。
heap模式和 offheap模式都使用内存作为最终存储介质,内存分配查询也都使用JavaNIO ByteBuffer 技术。二者不同的是,heap模式分配内存会调用ByteBuffer.allocate方法,从JVM提供的heap区分配; 而 offheap模式会调用ByteBuffer.allocateDirect方法,直接从操作系统分配。
这两种内存分配模式会对HBase实际工作性能产生一定的影响。影响最大的无疑是GC,相比 heap模式,offheap模式因为内存属于操作系统,所以大大降低了因为内存碎片导致Full GC的风险。除此之外,在内存分配以及读取方面,两者性能也有不同,比如,内存分配时,相比 offheap直接从操作系统分配内存,heap模式需要首先从操作系统分配内存再拷贝到JVM heap,因此更耗时;但是反过来,读取缓存时heap模式可以从JVM heap中直接读取,而 offheap模式则需要首先从操作系统拷贝到JVM heap再读取,因此更费时。
file模式和前面两者不同,它使用Fussion-IO或者SSD等作为存储介质,相比昂贵的内存,这样可以提供更大的存储容量,因此可以极大地提升缓存命中率。
heap模式
<property>
<name>hbase.bucketcache.ioenginename>
<value>heapvalue>
property>
<property>
<name>hbase.bucketcache.sizename>
<value>0.4value>
property>
ffheap模式
<property>
<name>hbase.bucketcache.ioenginename>
<value>offheapvalue>
property>
<property>
<name>hbase.bucketcache.sizename>
<value>0.4value>
property>
file模式
<property>
<name>hbase.bucketcache.ioenginename>
<value>filevalue>
property>
<property>
<name>hbase.bucketcache.sizename>
<value>10 * 1024value>
property>
<property>
<name>hbase.bucketcache.persistent.pathname>
<value>file:/cache_pathvalue>
property>