---
title: 分布式多级缓存
tags: [多级缓存, Cache]
sidebar_position: 10
slug: /advanced-guide/layering-cache
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# 分布式多级缓存
盘古开发框架基于[Laying Cahce](https://github.com/xiaolyuh/layering-cache),提供支持分布式环境的多级缓存功能。使用Caffeine作为一级本地缓存,Redis作为二级集中式缓存。支持缓存信息监控统计、支持缓存过期时间在注解上直接配置、支持缓存的自动刷新、缓存Key支持SpEL表达式、支持无感禁用一级缓存或二级缓存。通过缓存空值来解决缓存穿透问题、通过异步加载缓存的方式来解决缓存击穿和雪崩问题。
## 安装相关盘古模块
```jsx
com.gitee.pulanos.pangu
pangu-parent
latest.version.xxx
```
```jsx
com.gitee.pulanos.pangu
pangu-spring-boot-starter
```
```jsx
com.gitee.pulanos.pangu
pangu-cache-spring-boot-starter
```
## 本地配置
> 为便于理解,本文基于本地配置的方式编写。若改为标准的Nacos配置中心模式,请参阅:[使用指南->配置中心](/docs/advanced-guide/nacos-config-center)章节。
```jsx
spring.profiles.active=${spring.profiles.active:dev}
```
```jsx
spring.application.name=pangu-examples-cache-layering
# layering-cache 多级缓存
layering-cache.stats=false
# redis单机
layering-cache.redis.database=1
layering-cache.redis.host=localhost
layering-cache.redis.port=6379
layering-cache.redis.password=
# redis集群
#layering-cache.redis.password=
#layering-cache.redis.cluster=127.0.0.1:6379,127.0.0.1:6378
layering-cache.redis.serializer=com.github.xiaolyuh.redis.serializer.JacksonRedisSerializer
logging.level.root=INFO
logging.level.com.gitee.pulanos.pangu=INFO
```
### 关键配置项说明
|
配置项
| 配置说明
--- | ---
layering-cache.stats | 缓存监控统计开关,缺省true
layering-cache.redis.serializer | Redis序列化方式
## 基于注解声明
直接在需要缓存的方法上加上`@Cacheable`、`@CacheEvict`、`@CachePut`注解。(`@FirstCache`、`@SecondaryCache`为注解配置项,不能单独使用)
### @FirstCache
一级缓存配置项。
名称 | 默认值 | 说明
--- | --- | ---
initialCapacity | 10 | 缓存初始Size
maximumSize | 5000 | 缓存最大Size
expireTime | 9 | 缓存有效时间
timeUnit | TimeUnit.MINUTES | 时间单位,默认分钟
expireMode | ExpireMode.WRITE | 缓存失效模式,ExpireMode.WRITE:最后一次写入后到期失效,ExpireMode.ACCESS:最后一次访问后到期失效
### @SecondaryCache
二级缓存配置项。
名称 | 默认值 | 说明
--- | --- | ---
expireTime | 5 | 缓存有效时间
preloadTime | 1 | 缓存主动在失效前强制刷新缓存的时间,建议是 expireTime * 0.2
timeUnit | TimeUnit.HOURS | 时间单位,默认小时
forceRefresh | false | 是否强制刷新(直接执行被缓存方法)
magnification | 1 | 非空值和null值之间的时间倍率,默认是1。如expireTime=60秒,magnification=10,那么当缓存空值时,空值的缓存过期时间是60/10=6秒。
### @Cacheable
表示用的方法的结果是可以被缓存的,当该方法被调用时先检查缓存是否命中,如果没有命中再调用被缓存的方法,并将其返回值放到缓存中。
名称 | 默认值 | 说明
--- | --- | ---
cacheNames | 空字符串数组 | 缓存名称
key | 空字符串 | 缓存key,支持SpEL表达式
depict | 空字符串 | 缓存描述(在缓存统计页面会用到)
enableFirstCache | true | 是否启用一级缓存
firstCache | | 一级缓存配置
secondaryCache | | 二级缓存配置
```jsx title="@Cacheable 范例代码"
@Cacheable(cacheNames = "user", key = "#userId",
firstCache = @FirstCache(expireTime = 5),
secondaryCache = @SecondaryCache(expireTime = 10))
public UserVO getUser(Long userId) {
log.info("执行AnnotationBasedDemoService.getUser()");
// 从DB或其它资源渠道获取数据
UserVO userVO = new UserVO();
userVO.setId(userId);
userVO.setName("钱学森");
return userVO;
}
```
### @CachePut
将数据放到缓存中,新增缓存。
名称 | 默认值 | 说明
--- | --- | ---
cacheNames | 空字符串数组 | 缓存名称
key | 空字符串 | 缓存key,支持SpEL表达式
depict | 空字符串 | 缓存描述(在缓存统计页面会用到)
enableFirstCache | true | 是否启用一级缓存
firstCache | | 一级缓存配置
secondaryCache | | 二级缓存配置
```jsx title="@CachePut 范例代码"
@CachePut(cacheNames = "user", key = "#userVO.id",
firstCache = @FirstCache(expireTime = 10),
secondaryCache = @SecondaryCache(expireTime = 30))
public UserVO saveUser(UserVO userVO) {
log.info("执行AnnotationBasedDemoService.saveUser()");
return userVO;
}
```
### @CacheEvict
删除缓存。
名称 | 默认值 | 说明
--- | --- | ---
value | 空字符串数组 | 缓存名称,cacheNames的别名
cacheNames | 空字符串数组 缓存名称
key | 空字符串 | 缓存key,支持SpEL表达式
allEntries | false | 是否删除缓存中所有数据,默认情况下是只删除关联key的缓存数据,当该参数设置成 true 时 key 参数将无效
```jsx title="@CacheEvict 范例代码"
@CacheEvict(cacheNames = "user", key = "#userId")
public void delUser(Long userId) {
log.info("执行AnnotationBasedDemoService.delUser()");
}
@CacheEvict(cacheNames = "user", allEntries = true)
public void delAllUsers() {
log.info("执行AnnotationBasedDemoService.delAllUsers()");
}
```
## 基于API编程
可以直接使用Laying Cahce提供的API进行硬编码操作两级缓存,但不建议使用。这里就不做详细讲解了,可以在参考范例的`ApiBasedDemoService`类中找到相关的代码。
## 启动入口
需要`@EnableLayeringCache`注解的加持。如下代码所示。
```jsx {1}
@EnableLayeringCache
@SpringBootApplication
public class LayeringCachePanguApplication {
public static void main(String[] args) {
PanGuApplicationBuilder.init(LayeringCachePanguApplication.class).run(args);
}
}
```
快速QA:可以禁用一级缓存,只使用二级缓存吗?
必须可以。设置enableFirstCache = false 即可。
快速QA:可以禁用二级缓存,只使用一级缓存吗?
可以。设置二级缓存expireTime为0即可。
快速QA:我可以用Spring Cache的RedisTemplate API吗?
可以。laying cache和spring cahce相互隔离的,你只要在配置文件加入Spring Cache的配置,就可以注入RedisTemplate直接使用了。可以单独使用,也可以和laying cache混合使用。具体用法可以参考范例:pangu-examples-cache-single。
## 相关参考范例
- [pangu-examples-cache-layering](https://gitee.com/pulanos/pangu-framework/tree/master/pangu-examples/pangu-examples-empty-web):两级缓存(本地缓存+Redis集中缓存)范例
- [pangu-examples-cache-single](https://gitee.com/pulanos/pangu-framework/tree/master/pangu-examples/pangu-examples-cache-single):Spring Cache一级缓存API(RedisTemplate)范例
## 下一步
继续阅读其它章节获取您想要的答案或通过我们的[开发者社区](/docs/community)寻求更多帮助。