Appearance
Cache 使用说明
comet-cache 模块集成了 JetCache
两级缓存中间件,支持内存 + redis 的两级缓存,具体使用如下说明。
Jetcache 简介
JetCache 是一个基于 Java 的缓存系统封装,提供统一的 API 和注解来简化缓存的使用。
JetCache 提供了比 SpringCache 更加强大的注解,可以原生的支持 TTL、两级缓存、分布式自动刷新,还提供了 Cache
接口用于手工缓存操作。
当前有四个实现,RedisCache
、TairCache
(此部分未在github开源)、CaffeineCache
(in memory)、和一个简易的 LinkedHashMapCache
(in memory),也只支持添加新的实现。
要求
JetCache 需要 JDK1.8、Spring Framework4.0.8 以上版本。Spring Boot 为可选,需要 1.1.9 以上版本。如果不使用注解(仅使用 jetcache-core),Spring Framework 也是可选的,此时使用方式与 Guava/Caffeine cache 类似。
快速开始
基于 springboot 的方式基本配置
POM
xml
<dependency>
<groupId>com.dcits</groupId>
<artifactId>comet-cache</artifactId>
<version>${comet.version}</version>
</dependency>
${comet.version}
修改为具体的版本号。
springboot 配置方式
配置一个 spring boot 风格的 application.yml
文件,把他放到资源目录中,配置文件详细信息请看配置说明章节。
yaml
jetcache:
statIntervalMinutes: 15
areaInCacheName: false
local:
default:
type: linkedhashmap
keyConvertor: fastjson
remote:
default:
type: redis
keyConvertor: fastjson
valueEncoder: java
valueDecoder: java
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
host: 127.0.0.1
port: 6379
在项目启动类下,EnableMethodCache
,EnableCreateCacheAnnotation
这两个注解分别激活 Cached 和 CreateCache 注解。
java
package com.company.mypackage;
import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation;
import com.alicp.jetcache.anno.config.EnableMethodCache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableMethodCache(basePackages = "com.company.mypackage")
@EnableCreateCacheAnnotation
public class MySpringBootApp {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApp.class);
}
}
使用 @CreateCache
和 @Cached
注解添加缓存。
创建缓存实例
通过 @CreateCache
注解创建一个缓存实例,默认超时时间是 100 秒。
@CreateCache(expire = 100)
private Cache<Long, UserDO> userCache;
用起来就像 map 一样。
UserDO user = userCache.get(123L);
userCache.put(123L, user);
userCache.remove(123L);
创建一个两级(内存 + 远程)的缓存,内存中的元素个数限制在 50 个。
@CreateCache(name = "UserService.userCache", expire = 100, cacheType = CacheType.BOTH, localLimit = 50)
private Cache<Long, UserDO> userCache;
name
属性不是必须的,name
用于展示统计数据的使用。如果同一个 area
两个 @CreateCache
的 name
配置一样,它们生成的 Cache 将指向同一个实例。
创建方法缓存
使用 @Cached
方法可以为一个方法添加上缓存。JetCache 通过 Spring AOP 生成代理,来支持缓存功能。注解可以加在接口方法上也可以加在类方法上,但需要保证是个 Spring bean。
public interface UserService {
//添加缓存
@Cached(name="UserService.getUserById", expire = 3600)
User getUserById(long userId);
//更新缓存
@CacheUpdate(name="userCache.", key="#user.userId", value="#user")
void updateUser(User user);
//移除缓存元素
@CacheInvalidate(name="userCache.", key="#userId")
void deleteUser(long userId);
}
配置说明
yml 配置文件方式,如果没使用 springboot,直接配置 GlobalCacheConfig
是类似的:
jetcache:
statIntervalMinutes: 15
areaInCacheName: false
hidePackages: com.alibaba
local:
default:
type: caffeine
limit: 100
keyConvertor: fastjson
expireAfterWriteInMillis: 100000
otherArea:
type: linkedhashmap
limit: 100
keyConvertor: none
expireAfterWriteInMillis: 100000
remote:
default:
type: redis
keyConvertor: fastjson
valueEncoder: java
valueDecoder: java
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
host: ${redis.host}
port: ${redis.port}
otherArea:
type: redis
keyConvertor: fastjson
valueEncoder: kryo
valueDecoder: kryo
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
host: ${redis.host}
port: ${redis.port}
关于缓存的超时时间,有多个地方指定,生效规则如下:
- put 等方法上指定了超时时间,则以此时间为准
java
userCache.put("name", "dcits", 1000, TimeUnit.SECONDS);
put 等方法上未指定超时时间,使用 Cache 实例的默认超时时间
Cache 实例的默认超时时间,通过在
@CreateCache
和@Cached
上的 expire 属性指定,如果没有指定,使用 yml 中定义的全局配置;
例如 @Cached(cacheType=local)
使用 jetcache.local.default.expireAfterWriteInMillis
,如果仍未指定则是无穷大。
如果需要 redis 集群、读写分离、异步等特性,请参考以下配置:
从 JetCache2.2 版本开始,增加了对 lettuce 客户端的支持,JetCache 的 lettuce 支持提供了异步操作和 redis 集群支持。
application.yml 文件如下(这里省去了 local 相关的配置):
yaml
jetcache:
areaInCacheName: false
remote:
default:
type: redis.lettuce
keyConvertor: fastjson
uri: redis://127.0.0.1:6379/
#uri: redis-sentinel://127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381/?sentinelMasterId=mymaster
#readFrom: slavePreferred
如果使用 sentinel 做自动主备切换,uri 可以配置为 redis-sentinel://127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381/?sentinelMasterId=mymaster
如果是集群:
yaml
jetcache:
areaInCacheName: false
remote:
default:
type: redis.lettuce
keyConvertor: fastjson
#readFrom: slavePreferred
uri:
- redis://127.0.0.1:7000
- redis://127.0.0.1:7001
- redis://127.0.0.1:7002
@CreateCache 注解说明
在 Spring bean 中使用 @CreateCache 注解创建一个 Cache 实例,例如:
java
@CreateCache(expire = 100)
private Cache<Long, UserDO> userCache;
@CreateCache 属性说明
属性 | 默认值 | 说明 |
---|---|---|
area | “default” | 如果需要连接多个缓存系统,可在配置多个cache area,这个属性指定要使用的那个area的name |
name | 未定义 | 指定缓存的名称,不是必须的,如果没有指定,会使用类名+方法名。name会被用于远程缓存的key前缀。另外在统计中,一个简短有意义的名字会提高可读性。如果两个@CreateCache 的name 和area 相同,它们会指向同一个Cache 实例 |
expire | 未定义 | 该Cache实例的默认超时时间定义,注解上没有定义的时候会使用全局配置,如果此时全局配置也没有定义,则取无穷大 |
timeUnit | TimeUnit.SECONDS | 指定expire的单位 |
cacheType | CacheType.REMOTE | 缓存的类型,包括CacheType.REMOTE、CacheType.LOCAL、CacheType.BOTH。如果定义为BOTH,会使用LOCAL和REMOTE组合成两级缓存 |
localLimit | 未定义 | 如果cacheType为CacheType.LOCAL或CacheType.BOTH,这个参数指定本地缓存的最大元素数量,以控制内存占用。注解上没有定义的时候会使用全局配置,如果此时全局配置也没有定义,则取100 |
serialPolicy | 未定义 | 如果cacheType为CacheType.REMOTE或CacheType.BOTH,指定远程缓存的序列化方式。JetCache内置的可选值为SerialPolicy.JAVA和SerialPolicy.KRYO。注解上没有定义的时候会使用全局配置,如果此时全局配置也没有定义,则取SerialPolicy.JAVA |
keyConvertor | 未定义 | 指定KEY的转换方式,用于将复杂的KEY类型转换为缓存实现可以接受的类型,JetCache内置的可选值为KeyConvertor.FASTJSON和KeyConvertor.NONE。NONE表示不转换,FASTJSON通过fastjson将复杂对象KEY转换成String。如果注解上没有定义,则使用全局配置。 |
对于以上未定义默认值的参数,如果没有指定,将使用 yml 中指定的全局配置
方法级缓存说明
JetCache 方法缓存和 SpringCache 比较类似,它原生提供了 TTL 支持,以保证最终一致,并且支持二级缓存。JetCache2.4 以后支持基于注解的缓存更新和删除。
在 spring 环境下,使用 @Cached
注解可以为一个方法添加缓存,@CacheUpdate
用于更新缓存,@CacheInvalidate
用于移除缓存元素。注解可以加在接口上也可以加在类上,加注解的类必须是一个 spring bean,例如:
java
public interface UserService {
@Cached(name = "userCache.", key = "#userId", expire = 3600)
User getUserById(long userId);
@CacheUpdate(name = "userCache.", key = "#user.userId", value = "#user")
void updateUser(User user);
@CacheInvalidate(name = "userCache.", key = "#userId")
void deleteUser(long userId);
}
key 使用 Spring 的 SpEL 脚本来指定。如果要使用参数名(比如这里的 key="#userId"
),项目编译设置 target 必须为 1.8 格式,并且指定 javac 的 -parameters
参数,否则就要使用 key="args[0]"
这样按下标访问的形式。
@CacheUpdate
和 @CacheInvalidate
的 name 和 area 属性必须和 @Cached
相同,name 属性还会用做 cache 的 key 前缀。
@Cached 注解属性说明
属性 | 默认值 | 说明 |
---|---|---|
area | “default” | 如果在配置中配置了多个缓存area,在这里指定使用哪个area |
name | 未定义 | 指定缓存的唯一名称,不是必须的,如果没有指定,会使用类名+方法名。name会被用于远程缓存的key前缀。另外在统计中,一个简短有意义的名字会提高可读性。 |
key | 未定义 | 使用SpEL指定key,如果没有指定会根据所有参数自动生成。 |
expire | 未定义 | 超时时间。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为无穷大 |
timeUnit | TimeUnit.SECONDS | 指定expire的单位 |
cacheType | CacheType.REMOTE | 缓存的类型,包括CacheType.REMOTE、CacheType.LOCAL、CacheType.BOTH。如果定义为BOTH,会使用LOCAL和REMOTE组合成两级缓存 |
localLimit | 未定义 | 如果cacheType为LOCAL或BOTH,这个参数指定本地缓存的最大元素数量,以控制内存占用。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为100 |
localExpire | 未定义 | 仅当cacheType为BOTH时适用,为内存中的Cache指定一个不一样的超时时间,通常应该小于expire |
serialPolicy | 未定义 | 指定远程缓存的序列化方式。可选值为SerialPolicy.JAVA和SerialPolicy.KRYO。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为SerialPolicy.JAVA |
keyConvertor | 未定义 | 指定KEY的转换方式,用于将复杂的KEY类型转换为缓存实现可以接受的类型,当前支持KeyConvertor.FASTJSON和KeyConvertor.NONE。NONE表示不转换,FASTJSON可以将复杂对象KEY转换成String。如果注解上没有定义,会使用全局配置。 |
enabled | true | 是否激活缓存。例如某个dao方法上加缓存注解,由于某些调用场景下不能有缓存,所以可以设置enabled为false,正常调用不会使用缓存,在需要的地方可使用CacheContext.enableCache在回调中激活缓存,缓存激活的标记在ThreadLocal上,该标记被设置后,所有enable=false的缓存都被激活 |
cacheNullValue | false | 当方法返回值为null的时候是否要缓存 |
condition | 未定义 | 使用SpEL指定条件,如果表达式返回true的时候才去缓存中查询 |
postCondition | 未定义 | 使用SpEL指定条件,如果表达式返回true的时候才更新缓存,该评估在方法执行后进行,因此可以访问到#result |
@CacheInvalidate 注解说明
属性 | 默认值 | 说明 |
---|---|---|
area | “default” | 如果在配置中配置了多个缓存area,在这里指定使用哪个area,指向对应的@Cached定义。 |
name | 未定义 | 指定缓存的唯一名称,指向对应的@Cached定义。 |
key | 未定义 | 使用SpEL指定key |
condition | 未定义 | 使用SpEL指定条件,如果表达式返回true才执行删除,可访问方法结果#result |
@CacheUpdate 注解说明
属性 | 默认值 | 说明 |
---|---|---|
area | “default” | 如果在配置中配置了多个缓存area,在这里指定使用哪个area,指向对应的@Cached定义。 |
name | 未定义 | 指定缓存的唯一名称,指向对应的@Cached定义。 |
key | 未定义 | 使用SpEL指定key |
value | 未定义 | 使用SpEL指定value |
condition | 未定义 | 使用SpEL指定条件,如果表达式返回true才执行更新,可访问方法结果#result |
使用 @CacheUpdate
和 @CacheInvalidate
的时候,相关的缓存操作可能会失败(比如网络IO错误),所以指定缓存的超时时间是非常重要的。
@CacheRefresh 注解说明
属性 | 默认值 | 说明 |
---|---|---|
refresh | 未定义 | 刷新间隔 |
timeUnit | TimeUnit.SECONDS | 时间单位 |
stopRefreshAfterLastAccess | 未定义 | 指定该key多长时间没有访问就停止刷新,如果不指定会一直刷新 |
refreshLockTimeout | 60秒 | 类型为BOTH/REMOTE的缓存刷新时,同时只会有一台服务器在刷新,这台服务器会在远程缓存放置一个分布式锁,此配置指定该锁的超时时间 |
@CachePenetrationProtect
注解:
当缓存访问未命中的情况下,对并发进行的加载行为进行保护。 当前版本实现的是单 JVM 内的保护,即同一个 JVM 中同一个 key 只有一个线程去加载,其它线程等待结果。
对于以上未定义默认值的参数,如果没有指定,将使用 yml 中指定的全局配置。
Bulider 创建缓存
JetCache2 版本的 @Cached
和 @CreateCache
等注解都是基于 Spring4.X 版本实现的,在没有 Spring 支持的情况下,注解将不能使用。但是可以直接使用 JetCache 的 API 来创建、管理、监控 Cache,多级缓存也可以使用。
创建缓存
创建缓存的操作类似 guava/caffeine cache,例如下面的代码创建基于内存的 LinkedHashMapCache:
java
Cache<String, Integer> cache = LinkedHashMapCacheBuilder.createLinkedHashMapCacheBuilder()
.limit(100)
.expireAfterWrite(200, TimeUnit.SECONDS)
.buildCache();
创建 RedisCache:
java
GenericObjectPoolConfig pc = new GenericObjectPoolConfig();
pc.setMinIdle(2);
pc.setMaxIdle(10);
pc.setMaxTotal(10);
JedisPool pool = new JedisPool(pc, "localhost", 6379);
Cache<Long, OrderDO> orderCache = RedisCacheBuilder.createRedisCacheBuilder()
.keyConvertor(FastjsonKeyConvertor.INSTANCE)
.valueEncoder(JavaValueEncoder.INSTANCE)
.valueDecoder(JavaValueDecoder.INSTANCE)
.jedisPool(pool)
.keyPrefix("orderCache")
.expireAfterWrite(200, TimeUnit.SECONDS)
.buildCache();
多级缓存
在 2.2 以后通过下面的方式创建多级缓存:
java
Cache multiLevelCache = MultiLevelCacheBuilder.createMultiLevelCacheBuilder()
.addCache(memoryCache, redisCache)
.expireAfterWrite(100, TimeUnit.SECONDS)
.buildCache();
实际上,使用 MultiLevelCache
可以创建多级缓存,它的构造函数接收的是一个 Cache 数组(可变参数)。
如果是 2.2 之前的版本:
java
Cache memoryCache = ...
Cache redisCache = ...
Cache multiLevelCache = new MultiLevelCache(memoryCache, redisCache);
监控统计
如果要对 Cache 进行监控统计:
java
Cache orderCache = ...
CacheMonitor orderCacheMonitor = new DefaultCacheMonitor("OrderCache");
orderCache.config().getMonitors().add(orderCacheMonitor); // jetcache 2.2+, or call builder.addMonitor() before buildCache()
// Cache<Long, Order> monitedOrderCache = new MonitoredCache(orderCache, orderCacheMonitor); //before jetcache 2.2
int resetTime = 1;
boolean verboseLog = false;
DefaultCacheMonitorManager cacheMonitorManager = new DefaultCacheMonitorManager(resetTime, TimeUnit.SECONDS, verboseLog);
cacheMonitorManager.add(orderCacheMonitor);
cacheMonitorManager.start();
首先创建一个 CacheMonitor
,每个 DefaultCacheMonitor
只能用于一个 Cache。当 DefaultCacheMonitorManager
启动以后,会使用 slf4j 按指定的时间定期输出统计信息到日志中,DefaultCacheMonitor
构造时指定的名字会作为输出时 cache 的名字。
在组装多级缓存的过程中,可以给每个缓存安装一个 Monitor,这样可以监控每一级的命中情况。
也可以自己对统计信息进行处理,调用下面的构造方法创建 DefaultCacheMonitorManager
:
java
public DefaultCacheMonitorManager(int resetTime, TimeUnit resetTimeUnit, Consumer<StatInfo> statCallback)
参考链接
关于 jetCache 更多的使用请参考:https://github.com/alibaba/jetcache/wiki