分布式多级缓存.md 7.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
---
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表达式、支持无感禁用一级缓存或二级缓存。通过缓存空值来解决缓存穿透问题、通过异步加载缓存的方式来解决缓存击穿和雪崩问题。

X
xiongchun 已提交
15
## 安装相关盘古模块
16 17

<Tabs>
18
<TabItem value="parent" label="盘古Parent">
19 20 21 22 23 24 25 26 27 28

```jsx
<parent>
	<groupId>com.gitee.pulanos.pangu</groupId>
	<artifactId>pangu-parent</artifactId>
	<version>latest.version.xxx</version>
	<relativePath/>
</parent>
```
</TabItem>
29
<TabItem value="dependency1" label="基础模块">
30 31 32 33 34 35 36 37

```jsx
<dependency>
    <groupId>com.gitee.pulanos.pangu</groupId>
    <artifactId>pangu-spring-boot-starter</artifactId>
</dependency>
```
</TabItem>
38
<TabItem value="dependency2" label="缓存模块">
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

```jsx
<dependency>
	<groupId>com.gitee.pulanos.pangu</groupId>
	<artifactId>pangu-cache-spring-boot-starter</artifactId>
</dependency>
```
</TabItem>
</Tabs>

## 本地配置

> 为便于理解,本文基于本地配置的方式编写。若改为标准的Nacos配置中心模式,请参阅:[使用指南->配置中心](/docs/advanced-guide/nacos-config-center)章节。

<Tabs defaultValue="application-dev">
<TabItem value="application" label="application.properties">

```jsx
spring.profiles.active=${spring.profiles.active:dev}
```
</TabItem>
<TabItem value="application-dev" label="application-dev.properties">

```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
```
</TabItem>
</Tabs>

### 关键配置项说明

|<div style={{width:'120px'}}>配置项</div> | 配置说明
--- | --- 
layering-cache.stats | 缓存监控统计开关,缺省true
layering-cache.redis.serializer | Redis序列化方式

90
## 基于注解声明
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
直接在需要缓存的方法上加上`@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()");
}
```

186
## 基于API编程
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
可以直接使用Laying Cahce提供的API进行硬编码操作两级缓存,但不建议使用。这里就不做详细讲解了,可以在参考范例的`ApiBasedDemoService`类中找到相关的代码。

## 启动入口
需要`@EnableLayeringCache`注解的加持。如下代码所示。

```jsx {1}
@EnableLayeringCache
@SpringBootApplication
public class LayeringCachePanguApplication {
	public static void main(String[] args) {
		PanGuApplicationBuilder.init(LayeringCachePanguApplication.class).run(args);
	}
}
```

<details>
  <summary><b>快速QA:</b>可以禁用一级缓存,只使用二级缓存吗?</summary>
  <div>
  必须可以。设置enableFirstCache = false 即可。
  </div>
</details>

<details>
  <summary><b>快速QA:</b>可以禁用二级缓存,只使用一级缓存吗?</summary>
  <div>
  可以。设置二级缓存expireTime为0即可。
  </div>
</details>

<details>
  <summary><b>快速QA:</b>我可以用Spring Cache的RedisTemplate API吗?</summary>
  <div>
  可以。laying cache和spring cahce相互隔离的,你只要在配置文件加入Spring Cache的配置,就可以注入RedisTemplate直接使用了。可以单独使用,也可以和laying cache混合使用。具体用法可以参考范例:pangu-examples-cache-single。
  </div>
</details>

## 相关参考范例
- [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)寻求更多帮助。