Caffeine
Caffeine简介
- Caffeine 是基于Java 8的高性能,接近最佳的缓存库。 Caffeine使用Google Guava的API提供内存缓存。
- 在Caffeine中分为两种缓存,一个是有界缓存,一个是无界缓存,无界缓存不需要过期并且没有界限。
//下面创建的是无界缓存
Cache<String,String> cache = Caffeine.newBuilder().build();
//下面创建的是有界缓存
Cache<String,String> cache = Caffeine.newBuilder()
.maximumSize(100).build();
Caffeine使用
- maven使用Caffeine
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.6.2</version>
</dependency>
- 简单使用方式
Cache<String,String> cache = Caffeine.newBuilder()
.expireAfterWrite(100, TimeUnit.SECONDS)
.maximumSize(200)
.build();
- expireAfterWrite设置缓存在100秒内未写入会过期
- maximumSize设置最大长度为200,单位是MB
Caffeine与其他缓存对比
Caffeine原理
- Caffeine是基于 TinyLFU 实现的
Windows-TinyLFU
LFU、LRU、FIFO
- FIFO:first in first out。先进先出。判断被存储的时间,离目前最远的数据
优先被淘汰 - LRU:least recently used。最近最少使用。判断最近被使用的时间最远的数据优先被淘汰
- LFU:least frequently used。最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。
Windows-TinyLFU演变
- 传统的LFU收时间周期的影响比较大。所以各种LFU的变种出现了,基于时间周期进行衰减,或者在最近某个时间段内的频率。同样的LFU也会使用额外空间记录每一个数据访问的频率,即使数据没有在缓存中也需要记录,所以需要维护的额外空间很大。
- 命中率最高的策略就是 LFU,但是 LFU 有两个缺点:1. 需要维护比较大的元数据(比如说 key 的频数统计,缓存根据元数据来决定那些 key 需要清退);2. 频数变化可能会很快。
- 再回到LRU,我们的LRU也不是那么一无是处,LRU可以很好的应对突发流量的情况,因为他不需要累计数据频率。
- 所以W-TinyLFU结合了LRU和LFU,以及其他的算法的一些特点。
- TinyLFU的改进之处
- 1.对某个 key 是否放入缓存,有一个准入策略,需要判断把 key 放进缓存有利才会放;
- 2.更紧凑的数据结构
Caffeine比guava性能高的原因
- 在guava cache中读写操作夹杂着过期时间的处理,也就是在一次put操作中有可能还会做淘汰策略,所以其读写性能会受到一定影响。而Caffeine在读写操作上比guava高的原因在于Caffeine对淘汰策略的操作是异步操作(注意读写操作仍然是同步操作),他将事件提交至队列(RingBuffer)。然后会通过默认的ForkJoinPool.commonPool(),或者自己配置线程池进行取队列操作,然后再进行后续的淘汰,过期操作。
- 当然读写也是有不同的队列,在Caffeine中认为缓存读比写多很多,所以对于写操作时所有线程共享一个Ringbuffer。对于读操作,为每个线程配备了一个RingBuffer
Caffeine数据淘汰策略
-
在Caffeine所有的数据都在ConcurrentHashMap中,这个和guava cache不同,guava cache是自己实现了个类似ConcurrentHashMap的结构。在Caffeine中有三个记录引用的LRU队列
- Eden队列:在Caffeine中规定只能为缓冲容量的1%。这个队列中记录的是新到的数据,防止突发流量由于之前没有访问频率,从而导致被淘汰。
- Probation队列:称为缓刑队列,在这个队列就代表数据相对较冷,马上就要淘汰了。有效大小为size-eden队列大小-protected大小
- Protected队列:保护队列有效大小为(size-eden队列大小)×80%
-
淘汰策略
- 新数据进来首先进入Eden区,那么就算有突发的访问频率,也不会把这些数据给冲掉
- 被访问过一次以上数据会从Eden进入Probation,Probation称为缓刑区,一旦没有晋升到Protected,那么这个区的数据最有可能先死
- 从Probation的数据再被访问时会进入Protected区,在这个区称为保护区,这里的数据相对安全,但是一旦Protected区数据满了,被淘汰的数据,又会回到Probation区