jetcache
接入文档
官方文档
https://github.com/alibaba/jetcache/wiki
参考文档:https://blog.csdn.net/nb7474/article/details/84555665?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.pc_relevant_default&utm_relevant_index=1
jetcache
简介
阿里开源的缓存框架,它提供了比
spring cache
框架更加强大的注解。其注解支持原生的TTL,二阶段缓存(本地和远程),分布式的自动缓存刷新机制以及分布式锁,还可以自动采集对缓存的访问统计(包括TPS,缓存命中率等)。本地缓存可以使用LinkedHashMapCache
和CaffeineCache
,远程缓存可以使用RedisCache
。
spring boot
项目接入
添加maven依赖
<!--jetcache缓存 -->
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>${jetcache.latest.version}</version>
</dependency>
配置文件
参考文档:https://github.com/alibaba/jetcache/wiki/Config
配置示例:
jetcache:
# 每隔多长时间输出一次缓存访问统计信息,0表示不输出
statIntervalMinutes: 1
# 如果设置为`true`,生成的缓存名称中会带有`area`前缀(比如下面的`default_`,`longTime_`,`shortTime_`等等),建议设置为`false`
areaInCacheName: false
# 当缓存名称设置成自动生成时,匹配该前缀的会被切掉。建议手动设置缓存名称,方便查看缓存统计信息
hidePackages: com.springboot.cloud
# 本地缓存设置,type支持`caffeine`和`LinkedHashMapCache`
local: # 这里指定了3个`area`:default,longTime,shortTime可以按需配置
# 默认2小时本地缓存
default:
type: caffeine
keyConvertor: fastjson
expireAfterWriteInMillis: 3600000 # 写的过期时间
expireAfterAccessInMillis: 1800000 # 读的过期时间,本地缓存才支持
# 長時本地緩存,主要用于要求时效一般
longTime:
type: caffeine
keyConvertor: fastjson
expireAfterWriteInMillis: 300000
expireAfterAccessInMillis: 180000
# 短時本地緩存,主要用于要求时效较高的配置
shortTime:
type: caffeine
keyConvertor: fastjson
expireAfterWriteInMillis: 60000
expireAfterAccessInMillis: 40000
remote: # 这里指定了3个`area`:default,longTime,shortTime可以按需配置
# 默认2小时的远程缓存
default:
type: redis
expireAfterWriteInMillis: 43200000
keyConvertor: fastjson
valueEncoder: kryo # 只有remote缓存需要,支持`java`和`kryo`
valueDecoder: kryo # 只有remote缓存需要,支持`java`和`kryo`
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
host: ${REDIS_HOST}
port: ${REDIS_PORT}
password: ${REDIS_PASSWORD}
# 长时远程緩存,主要用于要求时效要求一般的集中式缓存
longTime:
type: redis
expireAfterWriteInMillis: 7200000
keyConvertor: fastjson
valueEncoder: kryo
valueDecoder: kryo
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
host: ${REDIS_HOST}
port: ${REDIS_PORT}
password: ${REDIS_PASSWORD}
# 短時远程緩存,主要用于要求时效较高的集中式缓存
shortTime:
type: redis
expireAfterWriteInMillis: 300000
keyConvertor: fastjson
valueEncoder: kryo
valueDecoder: kryo
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
host: ${REDIS_HOST}
port: ${REDIS_PORT}
password: ${REDIS_PASSWORD}
使用示例
-
@Cached
添加缓存(通常和@CacheUpdate
,@CacheInvalidate
配套使用)
核心参数释义:
area: 配置文件中关联的缓存域,比如上面的`default`,`longTime`,`shortTime`。默认`default`,继承缓存域的中的相关配置
cacheType: 枚举值。`BOTH`:本地和远程都缓存,`LOCAL`:本地缓存,`REMOTE`远程缓存
localLimit: 本地缓存条目限制,仅对本地缓存有效
key: 缓存的key,支持SpEL表达式
condition: 前置条件(方法执行前判断),结果为false则不添加缓存,支持SpEL表达式
postCondition: 后置条件(方法执行后判断),结果为false则不添加缓存,支持SpEL表达式(可以通过#result获取返回结果)。
代码示例:
@Cached(area = "longTime", cacheType = CacheType.BOTH, localLimit = 100,
name = "userCache::", key = "#userId", expire = 3600, condition = "", postCondition = "")
@Override
public User getUserById(int userId) {
// 访问db
return getFromDb();
}
-
@CacheUpdate
更新缓存
核心参数释义:
key: 缓存的key,支持SpEL表达式(建议设置一个bean,该bean专门用于条件判断,格式为:`bean('testService').方法名`),`testService`为bean的名称
condition: 后置条件(方法执行后判断),结果为false则不更新缓存,支持SpEL表达式(可以通过#result获取返回结果)。
multi: 如果`key`和`value`都是数组或者迭代器,设置为true时则以键值对的方式更新缓存
代码示例:
@CacheUpdate(name = "userCache::", key = "bean('testService').getKey()", value = "#user", condition = "bean('testService').predicate(#user,#result)")
@Override
public int updateUser(User user) {
// 访问db
return updateFromDb();
}
@Service
public class TestService implements ITestService {
@Override
public boolean predicate(User user, int size) {
return true;
}
@Override
public String getKey() {
return "2";
}
}
-
@CacheInvalidate
缓存失效
核心参数释义:
multi: 如果`key`和`value`都是数组或者迭代器,设置为true时则以键值对的方式使缓存失效
代码示例:
@CacheInvalidate(name = "userCache::", key = "#userId", multi = true)
@Override
public void deleteUser(int userId) {
// 访问db
return deleteFromDb();
}
-
@CreateCache
和@CacheRefresh
创建缓存并设置缓存自动刷新策略
@CreateCache
注解用来生成缓存
@CacheRefresh
注解对生成的缓存执行刷新策略。在remote
环境中,该刷新操作是全局锁定的(使用分布式锁),避免多个服务并发的刷新指定key的缓存
核心参数释义:
refresh: 定时刷新缓存(下面的`init`有示例)。在第一次调用`get`方法时候触发定时器,只是`put`不会触发定时器
stopRefreshAfterLastAccess: 最后一次调用`get`方法之后,多久停止对缓存的刷新
代码示例:
@CreateCache(name = "userCache::", expire = 1000, cacheType = CacheType.REMOTE)
@CacheRefresh(refresh = 10, stopRefreshAfterLastAccess = 20)
@CachePenetrationProtect
private Cache<Integer, User> userCache;
@PostConstruct
public void init() {
this.userCache.config().setLoader(this::loadFromDb);
}
private User loadFromDb(Integer key) {
log.info("Refresh value from key:{}", key);
User user = new User();
user.setId(key);
user.setName("clp");
return user;
}
@Override
public User getUserById(int userId) {
return userCache.get(userId);
}
@Override
public int updateUser(User user) {
this.userCache.put(user.getId(), user);
return user.getId();
}
- 分布式锁
使用tryLockAndRun
方式实现分布式锁的相关功能
代码示例:
@CreateCache(name = "userCache::", expire = 1000, cacheType = CacheType.REMOTE)
@CacheRefresh(refresh = 10, stopRefreshAfterLastAccess = 20)
@CachePenetrationProtect
private Cache<Integer, User> userCache;
@PostConstruct
public void init() {
this.userCache.config().setLoader(this::loadFromDb);
this.userCache.tryLockAndRun(1, 60, TimeUnit.SECONDS, () -> heavyDatabaseOperation());
}
@SneakyThrows
private void heavyDatabaseOperation(){
Thread.sleep(3000);
}
jetcache
统计功能
通过
statIntervalMinutes
参数设置统计打印周期,可以统计缓存的以下指标
qps:每秒请求次数
rate: 缓存命中率
get: 方法执行的次数
hit: 缓存命中次数
fail: 缓存失效的次数
expire: 过期数量
avgLoadTime: 平均加载时间
maxLoadTime: 最大加载时间
jetcache
缺点
上面说过
@Cached
注解通常和@CacheUpdate
,@CacheInvalidate
配套使用。其内部的实现原理是通过注解@EnableMethodCache
指定的basePackages
扫描所有标注了上述3个注解的方法,然后本地缓存。后续通过@CacheInvalidate
标注缓存失效,其首先会通过key
找对应的@Cached
,如果找不到则会抛出
异常:can't find @Cached definition with area=default...这里会产生一个问题:假设A服务通过@Cached
新增缓存,然后B服务通过@CacheUpdate
或
@CacheInvalidate
更新或删除缓存则会出现上述问题。还有通过一般方式添加的缓存(不通过jetcache
框架),想用@CacheInvalidate
失效也会报上述错误。