JAVA堆外缓存

2023-02-19  本文已影响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

其特性如下:

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的推荐服务计算中也有用到。

上一篇下一篇

猜你喜欢

热点阅读