【Java】高性能本地缓存-caffeine

高性能本地缓存-caffeine

简介

1、Caffeine 是基于 JAVA 8 的高性能缓存库。并且在 spring5 (springboot 2.x) 后,spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件
2、支持异步加载,事件提交队列
3、内部使用W-TinyLFU算法,它的命中率非常高,内存占用更加的小
4、一般在redis之后,做二级缓存
     

优势

性能比较:
8个线程同时从缓存中读取
【Java】高性能本地缓存-caffeine
8个线程同时从缓存中写入
【Java】高性能本地缓存-caffeine
6个线程读取,2个线程写入
【Java】高性能本地缓存-caffeine

使用场景

1、二级缓存

原生使用方式

### 填充策略

1、手动加载

// 初始化

public static void main(String[] args) {

Cache<String, Object> cache = Caffeine.newBuilder()

.expireAfterWrite(1, TimeUnit.SECONDS)

.expireAfterAccess(1, TimeUnit.SECONDS)

.maximumSize(10)

.build();

String key = "testKey";

//如果一个key不存在,那么会进入指定的函数生成value

Object value = cache.get(key, t -> setValue(key).apply(key));

cache.put("hello",value);

//判断是否存在如果不存返回null

Object ifPresent = cache.getIfPresent(key);

System.out.println(ifPresent);

//移除一个key

cache.invalidate(key);

}

public static Function<String, Object> setValue(String key){

return t -> key + "value";

}

2、同步加载

构造Cache时候,build方法传入一个CacheLoader实现类。实现load方法,通过key加载value

public static void main(String[] args) {

String key = "key";

LoadingCache<String, Object> cache = Caffeine.newBuilder()

.maximumSize(100)

.expireAfterWrite(1, TimeUnit.MINUTES)

.build(k -> setValue(key).apply(key));

System.out.println(cache.get(key));

}

public static Function<String, Object> setValue(String key){

return t -> key + "value";

}

3、异步加载

AsyncLoadingCache是继承自LoadingCache类的,异步加载使用Executor去调用方法并返回一个CompletableFuture。异步加载缓存使用了响应式编程模型

public static void main(String[] args) {

String key = "key";

AsyncLoadingCache<String, Object> cache = Caffeine.newBuilder()

.maximumSize(100)

.expireAfterWrite(1, TimeUnit.MINUTES)

.buildAsync(k -> setValue(key).get());

// 异步获取

CompletableFuture<Object> graph = cache.get(key);

graph.thenAccept(s -> {

System.out.println(s);

});

}

public static CompletableFuture<Object> setValue(String key){

return CompletableFuture.supplyAsync(() -> {

return key + "value";

});

}

springboot集成springboot-cache使用

1、添加jar依赖

<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>

2、配置@EnableCaching注解

@EnableCaching

@Configuration

public class LocalCacheConfig {

@Bean("caffeineCacheManager")

public CacheManager cacheManager(){

CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();

caffeineCacheManager.setCaffeine(Caffeine.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES).initialCapacity(100).maximumSize(5000));

return caffeineCacheManager;

}

}

3、使用

@Slf4j

@Service

@CacheConfig(cacheNames = "caffeineCacheManager")

public class SafetyInspectionTrackServiceImpl implements SafetyInspectionTrackService {

@Autowired

private SafetyInspectionTrackMapper safetyInspectionTrackMapper;

@Override

@Cacheable(key = "#id")

public SafetyInspectionTrackDO getById(Long id) {

log.info("进入缓存:{}",id);

return safetyInspectionTrackMapper.selectById(id);

}

@Override

@CacheEvict

public void clear(Long id){

log.info("清除缓存");

}

}

@Cacheable:

配置在 getUsersByName方法上表示其返回值将被加入缓存。同时在查询时,会先从缓存中

获取,若不存在才再发起对数据库的访问

@CachePut:

配置于方法上时,能够根据参数定义条件来进行缓存,其与 @Cacheable不同的是使用 

@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都

会执行该方法并将执行结果以键值对的形式存入指定的缓存中,所以主要用于数据新增和修改

操作上

@CacheEvict:

配置于方法上时,表示从缓存中移除相应数据

Caffeine常用配置说明

1、初始化参数

initialCapacity: 初始的缓存空间大小

maximumSize: 缓存的最大条数

maximumWeight: 缓存的最大权重

expireAfterAccess: 最后一次写入或访问后经过固定时间过期

expireAfterWrite: 最后一次写入后经过固定时间过期

refreshAfterWrite: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存

weakKeys: 打开key的弱引用

weakValues:打开value的弱引用

softValues:打开value的软引用

recordStats:开发统计功能

注意:

expireAfterWrite和expireAfterAccess同时存在时,以expireAfterWrite为准。

maximumSize和maximumWeight不可以同时使用

weakValues和softValues不可以同时使用

2、自动刷新

refreshAfterWrite就是设置写入后多就会刷新,expireAfterWrite和refreshAfterWrite

的区别是,当缓存过期后,配置了expireAfterWrite,则调用时会阻塞,等待缓存计算完成,返

回新的值并进行缓存,refreshAfterWrite则是返回一个旧值,并异步计算新值并缓存

3、回收策略

#### (1)基于大小

maximumSize 初始给定缓存大小,超过设置的值后,自动回收

#### (2)基于时间

expireAfterAccess:在最后一次访问或者写入后开始计时

expireAfterWrite:在最后一次写入缓存后开始计时

expireAfte:自定义策略

#### (3)基于引用

weakKeys:使用弱引用存储key

weakValues:使用弱引用存储value

softValues:使用软引用存储value 

软引用: 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。

弱引用: 弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存

淘汰策略算法

1、FIFO:先进先出

在这种淘汰算法中,先进入缓存的会先被淘汰,会导致命中率很低。

2、LRU:最近最少使用算法

每次访问数据都会将其放在我们的队尾,如果需要淘汰数据,就只需要淘汰队首即可。仍然有个问题,如果有个数据在 1 分钟访问了 1000次,再后 1 分钟没有访问这个数据,但是有其他的数据访问,就导致了我们这个热点数据被淘汰。

3、LFU:最近最少频率使用

利用额外的空间记录每个数据的使用频率,然后选出频率最低进行淘汰。这样就避免了 LRU 不能处理时间段的问题。

4、W-tinyLFU算法

详细介绍 https://www.cnblogs.com/liuji...

源码简析

【Java】高性能本地缓存-caffeine

1、在Caffeine中有个LocalCacheFactory类,他会根据你的配置进行具体Cache的创建。
【Java】高性能本地缓存-caffeine
2、在Caffeine中有个scheduleDrainBuffers方法,用来进行我们的过期任务的调度
【Java】高性能本地缓存-caffeine

常见问题(Faq)

#### 1、固定数据(Pinning Entries)

固定数据是不能通过驱逐策略去将数据删除的。当数据是一个有状态的资源时(如锁)

个人博客地址

以上是 【Java】高性能本地缓存-caffeine 的全部内容, 来源链接: utcz.com/a/87107.html

回到顶部