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

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

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

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):监听驱逐或无效操作的监听器

上一篇:使用instr 函数优化替换Like条件子句提高数据检索性能案例总结


下一篇:解决JDk1.6无法安装得问题