点击上方蓝字关注我!
高性能本地缓存
在将本地缓存前你肯定在想,本地缓存有么好讲的,不就是一个map么。把要缓存的数据存入map中,自己就能实现。但是这里有几个点我们要考虑:
“
并发-使用普通的Map还是线程安全的ConcurrentMap? 容量-Map的容量需要有多大? 过期策略-Map里的数据如果很久不用是不是需要定时清除? 驱逐策略-如果数据还没有过期,但是容量满了该怎么处理? ”
如果你也有这些问题那么请看下面的文章。
之前我介绍了Google的本地缓存Guava Cache,有兴趣的可以看看我的这篇文章:
“
”
但是我觉得这个本地缓存用起来不是很方便,性能也并不高。因此我推荐一个高性能本地缓存框架-Caffeine,Guava Cache的升级版,使用起来很方便。下面我们来看看它的使用示例。
性能
性能展示:
Read(100%)
Write(100%)
由上图我们看到:无论是读还是写,Caffeine的性能有多强。
使用示例
首先导入Maven依赖:
<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():
缓存失效时的监听。”
关于弱引用和内存泄漏,有兴趣的可以看看我写的这篇文章:
“
”
“
使用ThreadLocal怕内存泄漏?那你应该来看看这篇文章
”
Caffeine使用了线程安全,并发下性能优良的ConcurrentMap
我们开始从缓存中获取:
String valueFromCache = cache.get("lvshen", key -> getValue(key));
如上代码,我们从cache
中获取key为lvshen
的值,如果从cache
中获取不到,我们就从方法getValue(key)
中获取。一般来说查缓存有3步:
“
从缓存中查询,如果缓存中有值,返回 如果缓存中没有值,则从数据库中获取,并返回 将数据库中的值存入缓存中 ”
Caffeine本地缓存也是这个逻辑,为了模拟这个逻辑,我们两次从缓存中获取key为lvhsen
的值。第一次是从数据库中获取,会调用getValue()
方法,第二次会直接从缓存中获取。
运行结果如下:
调用了getValue方法....
测试结果:lvshen
测试结果2:lvshen
运行结果印证了上述逻辑。
除了自动清理缓存,我们也可以手动清理缓存:
cache.invalidate("lvshen");
Guava Cache和Caffeine很大的区别在于使用的淘汰算法,Guava Cache采用的LRU算法,而Caffeine使用的LFU算法的升级版TinyLFU算法,至于这LRU和LFU算法的区别,可以看看我写的这篇文章:
“
”
TinyLFU作为LFU算法的升级版,在性能上更加强大(高命中率、低内存占用),具体实现这里就不做详述。
当然我们也可以结合SpringBoot使用:
首先配置config
使用的时候直接注入:
@Autowired
Cache<String, Object> caffeineCache;
...
public void fun(String key) {
caffeineCache.put(key,"I am Lvshen");
}
我们也可以定义成注解的形式使用:
引入maven依赖
<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
使用如下:
@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)
”
往期推荐
扫码二维码
获取更多精彩
Lvshen_9
原文始发于微信公众号(Lvshen的技术小屋):开源的高性能本地缓存-Caffeine
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/262332.html