美文网首页
JAVA堆外缓存

JAVA堆外缓存

作者: 雪飘千里 | 来源:发表于2023-02-19 21:55 被阅读0次

    1 背景

    假如有一个服务的各项 JVM 的配置都比较合理的情况下,它的 GC 情况还是不容乐观。

    然后 dump 了一把内存,一顿分析之后发现有 2 个对象特别巨大,占了总存活堆内存的 76.8%。

    其中第 1 大对象是本地缓存, 使用 caffine 缓存组件,缓存自动刷新周期设定 1 小时,目的是尽量减少 IO 查询次数;

    由于占用空间很大,会导致频繁GC,影响系统性能。

    如何能尽量缓存较多的数据,同时避免过大的 GC 压力呢?

    可以把缓存对象移到堆外,这样可以不受堆内内存大小的限制;并且堆外内存,并不受 JVM GC 的管控,避免了缓存过大对 GC 的影响。

    堆外内存不受堆内内存大小的限制,只受服务器物理内存的大小限制。这三者之间的关系是这样的:物理内存=堆外内存+堆内内存。

    2 堆外缓存

    为了缓解在高并发,高写入操作下,堆内缓存组件造成的频繁GC问题,堆外缓存应运而生。堆内缓存是受JVM管控的,所以我们不必担心垃圾回收的问题。但是堆外缓存是不受JVM管控的,所以也不受GC的影响导致的应用暂停问题。但是由于堆外缓存的使用,是以byte数组来进行的,所以需要自己进行序列化反序列化操作。目前已知的知名开源项目中,netty4的buffer pool采用了堆外缓存实现,具体的比对信息截图如下:

    img

    带有Direct字眼的即为offheap堆外Buffer,x轴为分配的内存大小,Y轴为耗时。从上面可以看出,小块内存分配,JVM要稍微优秀一点;但是大块内存分配,明显的堆外缓存要优秀一些。由于堆外Buffer操作不受GC影响,实际上性能更好一些。但是需要的垃圾回收管控也需要自己去做,要麻烦很多。

    2 开源堆外缓存组件 OHC

    2.1 OHC 介绍

    OHC 全称为 off-heap-cache,即堆外缓存,是 2015 年针对 Apache Cassandra 开发的缓存框架,后来从 Cassandra 项目中独立出来,成为单独的类库,其项目地址为:https://github.com/snazy/ohc

    其特性如下:

    • 数据存储在堆外,只有少量元数据存储堆内,不影响 GC

    • 支持为每个缓存项设置过期时间

    • 支持配置 LRU、W_TinyLFU 驱逐策略

    • 能够维护大量的缓存条目

    • 支持异步加载缓存

    • 读写速度在微秒级别

    OHC具有低延迟、容量大、不影响GC的特性,并且支持使用方根据自身业务需求进行灵活配置。

    2.2 OHC 用法

    快速开始:

    OHCache ohCache = OHCacheBuilder.newBuilder().
     keySerializer(yourKeySerializer)
     .valueSerializer(yourValueSerializer)
     .build();
    

    可选配置项:

    图片

    在我们的服务中,设置 capacity 容量 12G,segmentCount 分段数 1024,序列化协议使用 kryo。

    2.3 优化效果

    切换到堆外缓存后,服务 YGC 降低到了 800ms / 每分钟,端到端的整体吞吐量上涨了约 20%。

    2.4 缺点

    缺点主要是序列化、反序列化,如果数据查询特别高频,那反序列化的成本就不可忽略了。

    3 应用场景

    OHC适合将离线数据进行本地缓存,从而节省访问远程数据库的时间。

    网上看到的具体应用场景,主要是在推荐服务中用到,比如 Java堆外缓存OHC在马蜂窝推荐引擎的应用 , vivo的推荐服务计算中也有用到。

    相关文章

      网友评论

          本文标题:JAVA堆外缓存

          本文链接:https://www.haomeiwen.com/subject/lhlbkdtx.html