BigMemory是用来避免GC对堆的开销,从几MB或GB大。 BigMemory通过直接的ByteBuffers使用JVM进程的内存地址空让盯敏间,不像其他原生Java对象接受GC管束。
EHCache(Terrcotta BigMemory)的 off-heap将你的对象从堆中脱离出来序列化,然后存储在一大块内存中,这就像它存储到磁盘上上一样,但它仍然在RAM中。对象在这种状态下不能直接使用,它们必须首先反序列化。也坦枝不受垃圾收集。序列化和反序列化会影响性能。(FST-serialization还是很快)。
使用堆外内存能够降低GC导致的暂停。
应用场景:
1.Session会话缓存,保存不激活的用户session,比如用户没有正常退出,我们也无法确定他会不会短时间内再回来,将其会话存则缺到堆外内存。一旦再次登录,无需访问数据库可再次激活。
2.计算结果的缓存,大量查询的结果等,击中率比较低的都可以迁移到堆外。
虽说hbase适合写多读少,但是hbase的读性能也是非常强悍的,hbase有如此好的读性能其中少不了BlockCache。BlockCache是regionserver级别的一种缓存,目前有三种实现方式:LruBlockCache、SlabCache和BucketCache,本文只对BucketCache的实现方式进行剖析。本文从BucketCache的内存模型、读写流程以及使用配置三方面进行说明。
BucketCache可以指定三种不同的存储介质:onHeap(java堆上内存)、offHeap(java堆外内存)和file(文件),不管使用哪种存储介质,内部的内存模型、读写流程都是一致的。
关于内存模型,BucketCache初始化时默认会申请14个不同大小的Bucket,一种Bucket存储一种指定BlockSize的数据块,每个Bucket的大小默认为2M,不同大小的Bucket之间的内存是可以互相使用的,从而保证的内存的使用率。BucketCache的内存模型如下图所示:
BucketCache中一共包括5个模块:ramCache、backingMap、ioEngine、writerThreads和BucketAllocator。
ramCache:block在写入BucketCache中指定的存储介质之前会先存储在ramCache这map中。
backingMap:记录写入BucketCache的BlockKey和对应Block在BucketCache中的offset。
ioEngine:实际写入存储介质的类,将Block数据写入对应地址的空间中。
writerThreads:多个线程,主要负责异步将Block写入存储介质中,每个线程都有一个支持并发的队列,用来存储Block。
BucketAllocator:为Block分配存储介质上的空间,主要就是获取一个存储介质上的offset,不同Bucket大小有对应的BucketAllocator。
蠢颤 BucketCache中的读写流程如下图所示:
1.进入到BucketCache类中的Block会首先将BlockKey和对应的Block存入到ramCache这个map,之后将该Block存入到对应writerThread线程对应的队列中。
2.writerThread线程持续地从队列中获取所有的Block。
3.调用对应Bucket大小的BucketAllocator为对应大小的Block分配内存,也就是获取一个存储介质上的offset。
4.调用ioEngine模块将Block写入到分配好的空间上。
cacheBlockWithWait:
cacheBlockWithWait方法是BucketCache写入Block的入口函数。
WriterThread.run
异步写入存储介质的后台宽慎线程。
doDrain
将队列中的Block写入ioEngine模块指定的存储介质中,并将对应的entry写入backingMap中。
1. 首先从RAMCache中查找。对于还没有来得及写入到bucket的缓存block,一定存储在RAMCache中。
2. 如果在RAMCache中没有找到,再在BackingMap中根据blockKey找到对应物理偏移地址offset。
3. 根据物理偏移地址offset可以直接从内存中查找对应的block数据。
getBlock:
从Bucketcache中获取对应的block的入口方法。
BucketCache分为三种存储介质:onHeap、offHeap、file。下面对这三种配置进行分别说明。
onHeap模式
offHeap模式
file模式
今天的分享就到这,有看不明白的地方一带巧败定是我写的不够清楚,所有欢迎提任何问题以及改善方法。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)