编程语言
首页 > 编程语言> > 新一代缓存之王Caffeine,甩了Guava几条街!

新一代缓存之王Caffeine,甩了Guava几条街!

作者:互联网


新一代缓存之王Caffeine,甩了Guava几条街!  

点击上方“芋道源码”,选择“”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 
我想把记忆缓存起来,等再次见到你,就能够很快认出你。 能够说出这么有哲理的话,得益于我对缓存的理解,以及对它的看重。没有了缓存,我的人生就没有了意义。

缓存是非常重要的,工作中大部分工作可以说是和缓存打交道。由于使用广泛,所以针对缓存系统的任何优化,如果能够提高一丁点儿性能,就会让人无比兴奋。

很长一段时间,我都在用Guava的LoadingCache。它和ConcurrentHashMap是非常像的,但在其上封装了一些好用的逐出策略和并发优化,就显得好用的多。

今天主要说的是Caffeine,中文名就是咖啡因,一种容易让人精神亢奋的物质。它可以说是Guava的重写,但是效率却非常的高,青出于蓝而胜于蓝。

下图是Caffeine的一张性能测试图。可以看到它的性能,甩了GuavaCache老远。

这是为什么呢?

后浪Caffeine一来,GuavaCache就已经OUT了。

Caffeine支持异步加载方式,直接返回CompletableFutures,相对于GuavaCache的同步方式,它不用阻塞等待数据的载入。另外,它的编程模型是友好的,省去了很多重复的工作。

GuavaCache是基于LRU的,而Caffeine是基于LRU和LFU的,结合了两者的优点。对这两个算法不太清楚的同学,可以参考xjjdog之前的文章:《3种堆内缓存算法,赠源码和设计思路》

两者合体之后,变成了新的W-TinyLFU算法,它的命中率非常高,内存占用更加的小,这是主要原因所在。

Caffeine另外一个比较快的原因,就是很多操作都使用了异步,把这些事件提交到队列里。队列使用的RingBuffer,看到这个名词,我不自觉的想到了lmax的Disruptor,它已经成了无锁高并发的代名词。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能 项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro 视频教程:https://doc.iocoder.cn/video/

我们决定拿线上的数据进行验证一下。事实上,大部分比较重要的Cache,我都已经使用Caffeine替换了,完成了骚气的升级。

由于它们的API长得非常像,这个过程是无痛的,连麻药都不需要打。

其中有个业务,有一个大的堆内缓存,缓存了用户数据。里面包含用户名、性别、地址、积分等属性,形成了一个JSON对象,但大小不超过1KB。通过灰度,根据不同的策略,我们测试了它的实际命中率。

策略1

命中率:

策略2

命中率 (依然是高一筹):

策略3

此时的命中率 :

Caffeine的命中率一直是领先的。命中率高,效率自然也就高。调整到50%以上,我们的缓存作用就很大了。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能 项目地址:https://gitee.com/zhijiantianya/yudao-cloud 视频教程:https://doc.iocoder.cn/video/

再放上官方的两张测试图:

(1) Read (75%) / Write (25%)

(2)Write (100%)

(3) Read (100%)

我们一直在提Caffeine的异步加载。那代码到底长什么样子呢?异步加载缓存使用了响应式编程模型,返回的是CompletableFuture对象。说实话,代码长得和Guava很像。

public static void main(String[] args) {
        AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder()
                .maximumSize(1000)
                .buildAsync(key -> slowMethod(key));

        CompletableFuture<String> g = loadingCache.get("test");
        String value = g.get();
    }

    static String slowMethod(String key) throws Exception {
        Thread.sleep(1000);
        return key + ".result";
    }

我记得前段时间翻Spring的源码时,也看到过它。

在SpringBoot里,通过提供一个CacheManager的Bean,即可与Springboot-cache进行集成,可以说是很方便了。

关键代码

//bean生成
@Bean("caffeineCacheManager")
public CacheManager cacheManager() {
    CaffeineCacheManager cacheManager = new CaffeineCacheManager();
    cacheManager.setCaffeine(Caffeine.newBuilder() .maximumSize(1000));
    return cacheManager;
}

//使用注入
@CacheConfig(cacheNames = "caffeineCacheManager")

//信息缓存
@Cacheable(key = "#id")


欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

点击上方“芋道源码”,选择“” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 我想把记忆缓存起来,等再次见到你,就能够很快认出你。 能够说出这么有哲理的话,得益于我对缓存的理解,以及对它的看重。没有了缓存,我的人生就没有了意义。 缓存是非常重要的,工作中大部分工作可以说是和缓存打交道。由于使用广泛,所以针对缓存系统的任何优化,如果能够提高一丁点儿性能,就会让人无比兴奋。 很长一段时间,我都在用Guava的LoadingCache。它和ConcurrentHashMap是非常像的,但在其上封装了一些好用的逐出策略和并发优化,就显得好用的多。 今天主要说的是Caffeine,中文名就是咖啡因,一种容易让人精神亢奋的物质。它可以说是Guava的重写,但是效率却非常的高,青出于蓝而胜于蓝。 下图是Caffeine的一张性能测试图。可以看到它的性能,甩了GuavaCache老远。 这是为什么呢? 后浪Caffeine一来,GuavaCache就已经OUT了。 Caffeine支持异步加载方式,直接返回CompletableFutures,相对于GuavaCache的同步方式,它不用阻塞等待数据的载入。另外,它的编程模型是友好的,省去了很多重复的工作。 GuavaCache是基于LRU的,而Caffeine是基于LRU和LFU的,结合了两者的优点。对这两个算法不太清楚的同学,可以参考xjjdog之前的文章:《3种堆内缓存算法,赠源码和设计思路》 两者合体之后,变成了新的W-TinyLFU算法,它的命中率非常高,内存占用更加的小,这是主要原因所在。 Caffeine另外一个比较快的原因,就是很多操作都使用了异步,把这些事件提交到队列里。队列使用的RingBuffer,看到这个名词,我不自觉的想到了lmax的Disruptor,它已经成了无锁高并发的代名词。 基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能 项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro 视频教程:https://doc.iocoder.cn/video/ 我们决定拿线上的数据进行验证一下。事实上,大部分比较重要的Cache,我都已经使用Caffeine替换了,完成了骚气的升级。 由于它们的API长得非常像,这个过程是无痛的,连麻药都不需要打。 其中有个业务,有一个大的堆内缓存,缓存了用户数据。里面包含用户名、性别、地址、积分等属性,形成了一个JSON对象,但大小不超过1KB。通过灰度,根据不同的策略,我们测试了它的实际命中率。 策略1 最大缓存1w用户 数据进入缓存后,5分钟失效(需要重新读取) 命中率: Caffeine 29.22 % Guava 21.95% 策略2 加大缓存数据量到6w用户 数据进入缓存后,20分钟失效,这个和Session有的一拼了 命中率 (依然是高一筹): Caffeine 56.04 % Guava 50.01% 策略3 直接加大缓存到15w用户 数据进入缓存后,30分钟失效 此时的命中率 : Caffeine 71.10 % Guava 62.76% Caffeine的命中率一直是领先的。命中率高,效率自然也就高。调整到50%以上,我们的缓存作用就很大了。 基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能 项目地址:https://gitee.com/zhijiantianya/yudao-cloud 视频教程:https://doc.iocoder.cn/video/ 再放上官方的两张测试图: (1) Read (75%) / Write (25%) (2)Write (100%) (3) Read (100%) 我们一直在提Caffeine的异步加载。那代码到底长什么样子呢?异步加载缓存使用了响应式编程模型,返回的是CompletableFuture对象。说实话,代码长得和Guava很像。 public static void main(String[] args) {         AsyncLoadingCache  asyncLoadingCache = Caffeine.newBuilder()                 .maximumSize(1000)                 .buildAsync(key -> slowMethod(key));         CompletableFuture  g = loadingCache.get("test");         String value = g.get();     }     static String slowMethod(String key) throws Exception {         Thread.sleep(1000);         return key + ".result";     } 我记得前段时间翻Spring的源码时,也看到过它。 在SpringBoot里,通过提供一个CacheManager的Bean,即可与Springboot-cache进行集成,可以说是很方便了。 关键代码 //bean生成 @Bean("caffeineCacheManager") public CacheManager cacheManager() {     CaffeineCacheManager cacheManager = new CaffeineCacheManager();     cacheManager.setCaffeine(Caffeine.newBuilder() .maximumSize(1000));     return cacheManager; } //使用注入 @CacheConfig(cacheNames = "caffeineCacheManager") //信息缓存 @Cacheable(key = "#id") 欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢: 已在知识星球更新源码解析如下: 最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。 提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

标签:
来源: