开源的高性能本地缓存-Caffeine

2022-05-05 19:11:40 浏览数 (1)

高性能本地缓存

在将本地缓存前你肯定在想,本地缓存有么好讲的,不就是一个map么。把要缓存的数据存入map中,自己就能实现。但是这里有几个点我们要考虑:

  • 并发-使用普通的Map还是线程安全的ConcurrentMap?
  • 容量-Map的容量需要有多大?
  • 过期策略-Map里的数据如果很久不用是不是需要定时清除?
  • 驱逐策略-如果数据还没有过期,但是容量满了该怎么处理?

如果你也有这些问题那么请看下面的文章。

之前我介绍了Google的本地缓存Guava Cache,有兴趣的可以看看我的这篇文章:

“Google的这个本地缓存真好用”

但是我觉得这个本地缓存用起来不是很方便,性能也并不高。因此我推荐一个高性能本地缓存框架-Caffeine,Guava Cache的升级版,使用起来很方便。下面我们来看看它的使用示例。

性能

性能展示:

Read(100%)

Write(100%)

由上图我们看到:无论是读还是写,Caffeine的性能有多强。

使用示例

首先导入Maven依赖:

代码语言:javascript复制
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>2.8.4</version>
</dependency>

测试代码:

我们先来创建一个缓存cache,这里我们定义了一些属性:

maximumSize():这里可以设置缓存数量上限。 expireAfterWriter():表示从最后一次写入后多久会过期。 weakKeys():key使用了弱引用。 weakValues():value值使用了弱引用,防止内存泄漏。 removeListener():缓存失效时的监听。 ”

Caffeine使用了线程安全,并发下性能优良的ConcurrentMap

我们开始从缓存中获取:

代码语言:javascript复制
String valueFromCache = cache.get("lvshen", key -> getValue(key));

如上代码,我们从cache中获取key为lvshen的值,如果从cache中获取不到,我们就从方法getValue(key)中获取。一般来说查缓存有3步:

  • 从缓存中查询,如果缓存中有值,返回
  • 如果缓存中没有值,则从数据库中获取,并返回
  • 将数据库中的值存入缓存中

Caffeine本地缓存也是这个逻辑,为了模拟这个逻辑,我们两次从缓存中获取key为lvhsen的值。第一次是从数据库中获取,会调用getValue()方法,第二次会直接从缓存中获取。

运行结果如下:

代码语言:javascript复制
调用了getValue方法....
测试结果:lvshen
测试结果2:lvshen

运行结果印证了上述逻辑。

除了自动清理缓存,我们也可以手动清理缓存:

代码语言:javascript复制
cache.invalidate("lvshen");

Guava Cache和Caffeine很大的区别在于使用的淘汰算法,Guava Cache采用的LRU算法,而Caffeine使用的LFU算法的升级版TinyLFU算法,至于这LRU和LFU算法的区别,可以看看我写的这篇文章:

“【技术干货】淘汰算法LRU与LFU”

TinyLFU作为LFU算法的升级版,在性能上更加强大(高命中率、低内存占用),具体实现这里就不做详述。

当然我们也可以结合SpringBoot使用:

首先配置config

使用的时候直接注入:

代码语言:javascript复制
@Autowired
Cache<String, Object> caffeineCache;

...
public void fun(String key) {
    caffeineCache.put(key,"I am Lvshen");
}

我们也可以定义成注解的形式使用:

引入maven依赖

代码语言:javascript复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

配置config

使用如下:

代码语言:javascript复制
@CachePut(key = "#userInfo.id")
public void addUser(User userInfo) {
    //这里模拟存入数据库中
    userMap.put(userInfo.getId(), userInfo);
}

@Cacheable(key = "#id")
public User getByName(Integer id) {
    //先从缓存中获取,缓存中没有,再从数据库中获取
    return userMap.get(id);
}

这样我们也能实现SpringBoot和Caffeine的融合使用。

官方文档

本篇文章只是对Caffeine做一个入门的介绍,想要深入了解的童鞋可以看看官方文档。

官方文档

Caffeine的官方使用文档如下:

“(https://github.com/ben-manes/caffeine/wiki/Policy-zh-CN) ”

0 人点赞