Caffeine Cache进阶本地缓存之王

3,194 阅读4分钟

图片

做一个单纯的程序汪,分享干货,聊聊人生。

微信公众号:后端架构进阶

关注我发现更多的干货,微服务、Spring源码、JVM、SpringCloud Alibaba、K8S等。

如果你觉得本文对你有帮助,麻烦给我点个赞,感谢支持!

互联网软件神速发展,用户的体验度是判断一个软件好坏的重要原因,所以缓存就是必不可少的一个神器。

在多线程高并发场景中往往是离不开cache的,需要根据不同的应用场景来需要选择不同的cache,比如分布式缓存如redis、memcached,还有本地(进程内)缓存如ehcache、GuavaCache、Caffeine。

说起Guava Cache,很多人都不会陌生,它是Google Guava工具包中的一个非常方便易用的本地化缓存实现,基于LRU算法实现,支持多种缓存过期策略。

但是,Guava Cache的性能一定是最好的吗?也许,曾经,它的性能是非常不错的。但所谓长江后浪推前浪,总会有更加优秀的技术出现。今天,我就来介绍一个比Guava Cache性能更高的缓存框架:Caffeine。

一、性能比较

场景一、8个线程读,100%的读操作

图片

场景二、6个线程读,2个线程写,也就是75%的读操作,25%的写操作

图片

场景三:8个线程写,100%的写操作

图片

看到这里,是不是应该反手给个666?而且这是官方给的测试结果。虽说Caffeine是基于Guava Cache改版。但是这样的数据绝对能勾起你的兴趣。

那么,问题来了,怎么使用呢?别急,客官,听我细说。

二、集成使用


在我们的项目中的使用也是非常简单,首先引入依赖,我这里版本号用的是最新的。可以按照自己的需求选择版本号。

<dependency>
      <groupId>com.github.ben-manes.caffeine</groupId>
      <artifactId>caffeine</artifactId>
      <version>3.0.4</version>
</dependency>

加载代码的简单测试如下所示,通过CacheBuilder来构建缓存。设置初始化值、最大值、过期时间以及没查到数据的时候的加载逻辑。

public static void main(String[] args) {
      LoadingCache<String, String> build = CacheBuilder
          .newBuilder() 
          .initialCapacity(1)   # 初始大小
          .maximumSize(100)     # 最大容量
          .expireAfterWrite(1, TimeUnit.DAYS) # 过期时间
          .build(new CacheLoader<String, String>() {
          //当调用get取值的时候,如果key没有对应的值,就调用这个方法进行加载
           @Override
           public String load(String key)  {
                return "";
           }
      });
}

三、过期策略

在Caffeine中分为两种缓存,一个是有界缓存,一个是无界缓存,无界缓存不需要过期并且没有界限。

有界缓存提供了三个过期API

  • expireAfterWrite:代表着写了之后多久过期。(上面列子就是这种方式)
  • expireAfterAccess:代表着最后一次访问了之后多久过期。
  • expireAfter:在expireAfter中需要自己实现Expiry接口,这个接口支持create、update以及access之后多久过期。

最后这个API和前面两个API互斥。需要你告诉缓存框架,他应该在具体的某个时间过期,也就是通过前面的重写create、update以及access的方法,获取具体的过期时间。

四、更新策略

Caffeine提供了refreshAfterWrite()方法来让我们进行写后多久更新策略。

LoadingCache<String, String> build = CacheBuilder
      .newBuilder()
      .refreshAfterWrite(1, TimeUnit.DAYS) # 多久后刷新
      .build(new CacheLoader<String, String>() {
          @Override
          public String load(String key)  {
             return "";
          }
    });
}

上面这种方式到一天后也不会刷新,因为必有在1天后这个缓存再次访问才能刷新,如果没人访问,那么永远也不会刷新。

自动刷新他是怎么做的呢?自动刷新只存在读操作之后,也就是我们 afterRead() 这个方法,其中有个方法叫 refreshIfNeeded(),他会根据你是同步还是异步然后进行刷新处理。

五、统计

使用Caffeine.recordStats(),您可以打开统计信息收集。Cache.stats() 方法返回提供统计信息的CacheStats。

Cache<Key, Graph> graphs = Caffeine.newBuilder()
      .maximumSize(1000)
      .recordStats()
      .build();

统计信息的值中包含的数据如下:

  • hitRate():返回命中与请求的比率
  • hitCount(): 返回命中缓存的总数
  • evictionCount():缓存逐出的数量
  • averageLoadPenalty():加载新值所花费的平均时间

用了之后感觉真的爽,从GuavaCache切换过来的成本也很低。快去试试吧!喜欢记得关注我哟~

之前的文章都做了总结,感兴趣直接查看,传送门:

历史文章汇总

总结

以上就是之前的内容的总结和分享,感谢各位大佬的 关注点赞收藏

微信公众号:后端架构进阶

更多文章正在赶来,喜欢记得给我点个 👍 ,感谢支持!

公众号文章同步更新!关注我,不迷路!