Caffeine 本地缓存框架原理及用法总结

简介: Caffeine 本地缓存框架原理及用法总结

常用缓存算法:
First in first out(FIFO)队列:先进先出,最先进入的数据最先被淘汰,缺点:忽略数据访问频率和访问次数。
Least recently used (LRU):最近最少使用算法,即:如果数据最近被访问过,那么将来被访问的概率也更大。LRU使用一个链表来实现,新插入的数据会被添加到链表的头部;当缓存命中后,就会再将数据移动到链表的头部;如果链表满的时候,就会将链表尾部的数据丢弃。
【命中率】如果存在热点数据,LRU的效率很好,然而对于偶发性的、周期性的批量操作就会导致LRU命中率急剧下降,缓存污染情况比较严重。
【复杂度】实现简单。
【代价】访问数据命中时需要遍历链表,并找到命中的数据块索引位置,然后再将数据移动到链表头部。

LRU.png

Least frequently used (LFU):最近经常使用算法,即:如果数据过去被访问多次,那么将来被访问的频率也更高。

Caffeine缓存算法:它结合了LRU和LFU两种算法来管理缓存。

Caffeine数据结构:
Caffeine采用的是readBuffer和writeBuffer。它使用一个Long数组来存储key的访问频率。Long的64位被分为4个段,每个段占16位。首先,根据key算出hash值,使用hash值来计算处于4段中哪个段;其次,计算出4个段的具体位置,并设定当前位置的频率;最终以这4个频率值的最小值来代表该key的访问频率。
ringbuffer默认为16,其数组大小是256,假设引用大小为4字节(ringbuffer中存储的是引用),缓存行大小为64。所以这里每个缓存行只存一个数据,所以cas操作追加16,即数组中每16个元素只有一个有效存储,以空间换时间。

高性能读写操作:
借鉴数据库的WAL思想,读写操作后,将操作记录(判断数据是否过期;统计频率;记录读写统计命中率等)记载到缓冲区,再异步处理,提高了性能。
WAL(Write-Ahead Logging)的核心思想是:在数据写入到数据库之前,先写入到日志.再将日志记录变更到存储器中。

Caffeine缓存的三种回收策略
基于大小(size-based):maximumSize
基于时间(time-based):

     expireAfterAccess 最后一次访问过期计时
     expireAfterWrite  最后一次写入时过期计时

基于引用(reference-based):仅对软引用、弱引用过期处理

使用方法:

// 初始化Caffeine对象
@Bean
public Cache<String, Object> caffeineCacheInstance() {
Cache<String, Object> caffeineCache = Caffeine.newBuilder().initialCapacity(initialCapacity)
// 设置永不过期,默认300年
.expireAfterAccess(Long.MAX_VALUE, TimeUnit.DAYS)
.expireAfterWrite(Long.MAX_VALUE, TimeUnit.DAYS)
// 设置移除监听器
.removalListener(new CacheRemoveListener())
// 不限容量
//.maximumSize(maximumSize)
.build();
return caffeineCache;
}
// 增加处理缓存移除监听器类CacheRemoveListener
public class CacheRemoveListener implements RemovalListener<Object, Object> {
@Override
public void onRemoval(@Nullable Object key, @Nullable Object value, @Null RemovalCause cause) {
// 缓存被回收或过期时处理
if(cause.equals(RemovalCause.COLLECTED) || cause.equals(RemovalCause.EXPIRED)) {
// 当对象被回收或过期时需要处理
return;
}
// 缓存更新时处理
if(cause.equals(RemovalCause.REPLACED)) {
logger.warn("Caffeine " + cause + " OK, key-value, " + key + ":" + value);
}
}
}

用法:在具体的@Service类中引用
@Autowired
private Cache<String, Object> caffeineCacheInstance;
存放:caffeineCacheInstance.put(key, value);
读取:Object value = caffeineCacheInstance.getIfPresent(key);

使用时需要注意点:
(1)初始化本地缓存数据
(2)容量评估,不要超出内存容量
(3)缓存命中率
(4)垃圾回收
(5)性能测试

相关名词解释:
驱逐(eviction):由于满足了某种驱逐策略,后台自动进行的删除操作
无效(invalidation):表示由调用方手动删除缓存
移除(removal):监听驱逐或无效操作的监听器

相关文章
|
3月前
|
缓存 NoSQL Java
什么是缓存?如何在 Spring Boot 中使用缓存框架
什么是缓存?如何在 Spring Boot 中使用缓存框架
127 0
|
2月前
|
存储 缓存 自然语言处理
SCOPE:面向大语言模型长序列生成的双阶段KV缓存优化框架
KV缓存是大语言模型(LLM)处理长文本的关键性能瓶颈,现有研究多聚焦于预填充阶段优化,忽视了解码阶段的重要性。本文提出SCOPE框架,通过分离预填充与解码阶段的KV缓存策略,实现高效管理。SCOPE保留预填充阶段的关键信息,并在解码阶段引入滑动窗口等策略,确保重要特征的有效选取。实验表明,SCOPE仅用35%原始内存即可达到接近完整缓存的性能水平,显著提升了长文本生成任务的效率和准确性。
172 3
SCOPE:面向大语言模型长序列生成的双阶段KV缓存优化框架
|
6月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
172 1
|
6月前
|
缓存 Java Spring
Java本地高性能缓存实践问题之Caffeine中设置刷新机制的问题如何解决
Java本地高性能缓存实践问题之Caffeine中设置刷新机制的问题如何解决
201 1
|
6月前
|
存储 缓存 Java
Java本地高性能缓存实践问题之如何定义Caffeine的缓存
Java本地高性能缓存实践问题之如何定义Caffeine的缓存
|
6月前
|
缓存 Java
Java本地高性能缓存实践问题之Caffeine缓存库中基于时间设置驱逐策略的问题如何解决
Java本地高性能缓存实践问题之Caffeine缓存库中基于时间设置驱逐策略的问题如何解决
108 0
|
6月前
|
缓存 Java
Java本地高性能缓存实践问题之使用Caffeine的Cache接口来查找一个缓存元素的问题如何解决
Java本地高性能缓存实践问题之使用Caffeine的Cache接口来查找一个缓存元素的问题如何解决
|
5月前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
254 24
|
5月前
|
存储 消息中间件 缓存
本地缓存Caffeine系列(三)
本地缓存Caffeine系列(三)
|
5月前
|
缓存 NoSQL 算法
本地缓存Caffeine系列(四)
本地缓存Caffeine系列(四)