Add comprehensive documentation for system architecture and best practices

This commit is contained in:
Cursor Agent
2025-06-18 08:04:08 +00:00
parent bbf6135e39
commit d8faa09372
9 changed files with 5748 additions and 0 deletions

View File

@@ -0,0 +1,665 @@
# 缓存策略详解
## Redis 缓存架构
### 缓存层次结构
```
应用层 -> 本地缓存 (Caffeine) -> Redis 缓存 -> 数据库
```
### 核心组件
- **Spring Cache**: 统一缓存抽象
- **Redis**: 分布式缓存存储
- **Caffeine**: 本地缓存提升性能
- **Redisson**: Redis 客户端和分布式锁
## 缓存配置
### Redis 连接配置
```yaml
spring:
data:
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
timeout: 2000ms
lettuce:
pool:
max-active: 200
max-idle: 20
min-idle: 5
max-wait: 1000ms
```
### 缓存管理器配置
```java
@Configuration
@EnableCaching
public class CacheConfiguration {
@Bean
@Primary
public CacheManager cacheManager(RedisTemplate<String, Object> redisTemplate) {
// Redis 缓存管理器
RedisCacheManager.Builder builder = RedisCacheManager
.RedisCacheManagerBuilder
.fromConnectionFactory(redisTemplate.getConnectionFactory())
.cacheDefaults(buildCacheConfiguration());
return builder.build();
}
@Bean("localCacheManager")
public CacheManager localCacheManager() {
// 本地缓存管理器
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(30, TimeUnit.MINUTES));
return cacheManager;
}
}
```
## 缓存使用模式
### 基础缓存注解
```java
@Service
public class UserServiceImpl implements UserService {
/**
* 查询缓存
*/
@Cacheable(value = "user", key = "#id")
public UserDO getUser(Long id) {
return userMapper.selectById(id);
}
/**
* 更新缓存
*/
@CachePut(value = "user", key = "#user.id")
public UserDO updateUser(UserDO user) {
userMapper.updateById(user);
return user;
}
/**
* 删除缓存
*/
@CacheEvict(value = "user", key = "#id")
public void deleteUser(Long id) {
userMapper.deleteById(id);
}
/**
* 清空缓存
*/
@CacheEvict(value = "user", allEntries = true)
public void clearUserCache() {
// 清空所有用户缓存
}
}
```
### 条件缓存
```java
// 条件缓存 - 只有状态为启用的用户才缓存
@Cacheable(value = "user", key = "#id", condition = "#user.status == 1")
public UserDO getUser(Long id) {
return userMapper.selectById(id);
}
// 排除缓存 - 管理员用户不缓存
@Cacheable(value = "user", key = "#id", unless = "#result.username == 'admin'")
public UserDO getUser(Long id) {
return userMapper.selectById(id);
}
```
### 自定义缓存键
```java
// 复合键
@Cacheable(value = "user", key = "#tenantId + ':' + #username")
public UserDO getUserByUsername(Long tenantId, String username) {
return userMapper.selectOne(new LambdaQueryWrapper<UserDO>()
.eq(UserDO::getTenantId, tenantId)
.eq(UserDO::getUsername, username));
}
// 使用 SpEL 表达式
@Cacheable(value = "user", key = "T(String).valueOf(#user.tenantId).concat(':').concat(#user.username)")
public UserDO createUser(UserCreateReqVO reqVO) {
// 创建用户逻辑
}
```
## Redis 数据结构使用
### 字符串 (String)
```java
@Component
public class StringCacheService {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 设置缓存
*/
public void set(String key, String value, Duration timeout) {
stringRedisTemplate.opsForValue().set(key, value, timeout);
}
/**
* 获取缓存
*/
public String get(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
/**
* 原子递增
*/
public Long increment(String key) {
return stringRedisTemplate.opsForValue().increment(key);
}
}
```
### 哈希 (Hash)
```java
@Component
public class HashCacheService {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 设置 Hash 字段
*/
public void hset(String key, String field, String value) {
stringRedisTemplate.opsForHash().put(key, field, value);
}
/**
* 获取 Hash 字段
*/
public String hget(String key, String field) {
return (String) stringRedisTemplate.opsForHash().get(key, field);
}
/**
* 获取所有 Hash 字段
*/
public Map<Object, Object> hgetAll(String key) {
return stringRedisTemplate.opsForHash().entries(key);
}
}
```
### 列表 (List)
```java
@Component
public class ListCacheService {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 左推入
*/
public void lpush(String key, String value) {
stringRedisTemplate.opsForList().leftPush(key, value);
}
/**
* 右弹出
*/
public String rpop(String key) {
return stringRedisTemplate.opsForList().rightPop(key);
}
/**
* 获取列表
*/
public List<String> range(String key, long start, long end) {
return stringRedisTemplate.opsForList().range(key, start, end);
}
}
```
### 集合 (Set)
```java
@Component
public class SetCacheService {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 添加成员
*/
public void sadd(String key, String... values) {
stringRedisTemplate.opsForSet().add(key, values);
}
/**
* 获取所有成员
*/
public Set<String> smembers(String key) {
return stringRedisTemplate.opsForSet().members(key);
}
/**
* 判断是否存在
*/
public Boolean sismember(String key, String value) {
return stringRedisTemplate.opsForSet().isMember(key, value);
}
}
```
### 有序集合 (ZSet)
```java
@Component
public class ZSetCacheService {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 添加成员
*/
public void zadd(String key, String value, double score) {
stringRedisTemplate.opsForZSet().add(key, value, score);
}
/**
* 获取排名范围
*/
public Set<String> zrange(String key, long start, long end) {
return stringRedisTemplate.opsForZSet().range(key, start, end);
}
/**
* 获取分数范围
*/
public Set<String> zrangeByScore(String key, double min, double max) {
return stringRedisTemplate.opsForZSet().rangeByScore(key, min, max);
}
}
```
## 缓存键设计规范
### 键命名规范
```java
public class RedisKeyConstants {
/**
* 用户缓存
* KEY 格式user:{id}
* 过期时间30 分钟
*/
public static final String USER = "user";
/**
* 验证码缓存
* KEY 格式captcha:{uuid}
* 过期时间5 分钟
*/
public static final String CAPTCHA = "captcha";
/**
* 权限缓存
* KEY 格式permission:{userId}
* 过期时间1 小时
*/
public static final String PERMISSION = "permission";
/**
* 字典缓存
* KEY 格式dict:{type}
* 过期时间:永不过期
*/
public static final String DICT = "dict";
}
```
### 键生成工具
```java
@Component
public class RedisKeyBuilder {
/**
* 构建用户缓存键
*/
public static String buildUserKey(Long userId) {
return RedisKeyConstants.USER + ":" + userId;
}
/**
* 构建验证码缓存键
*/
public static String buildCaptchaKey(String uuid) {
return RedisKeyConstants.CAPTCHA + ":" + uuid;
}
/**
* 构建权限缓存键
*/
public static String buildPermissionKey(Long userId) {
return RedisKeyConstants.PERMISSION + ":" + userId;
}
/**
* 构建租户级别缓存键
*/
public static String buildTenantKey(String prefix, Long tenantId, Object suffix) {
return prefix + ":" + tenantId + ":" + suffix;
}
}
```
## 分布式锁
### Redisson 分布式锁
```java
@Component
public class DistributedLockService {
@Resource
private RedissonClient redissonClient;
/**
* 尝试获取锁
*/
public boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
/**
* 释放锁
*/
public void unlock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
/**
* 锁模板方法
*/
public <T> T executeWithLock(String lockKey, long waitTime, long leaseTime,
TimeUnit unit, Supplier<T> supplier) {
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(waitTime, leaseTime, unit)) {
return supplier.get();
} else {
throw new ServiceException("获取锁失败");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ServiceException("获取锁被中断");
} finally {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
```
### 分布式锁应用
```java
@Service
public class OrderService {
@Resource
private DistributedLockService lockService;
/**
* 创建订单(防重复提交)
*/
public OrderDO createOrder(OrderCreateReqVO reqVO) {
String lockKey = "order:create:" + reqVO.getUserId();
return lockService.executeWithLock(lockKey, 5, 10, TimeUnit.SECONDS, () -> {
// 检查重复订单
validateDuplicateOrder(reqVO);
// 创建订单
return doCreateOrder(reqVO);
});
}
}
```
## 缓存预热
### 应用启动预热
```java
@Component
public class CacheWarmUpService {
@Resource
private DictDataService dictDataService;
@Resource
private ConfigService configService;
@EventListener(ApplicationReadyEvent.class)
public void warmUpCache() {
log.info("[warmUpCache][开始预热缓存]");
// 预热字典缓存
dictDataService.warmUpCache();
// 预热配置缓存
configService.warmUpCache();
log.info("[warmUpCache][预热缓存完成]");
}
}
```
### 定时预热
```java
@Component
public class CacheScheduleService {
/**
* 定时刷新热点数据
*/
@Scheduled(fixedRate = 300000) // 5分钟执行一次
public void refreshHotData() {
// 刷新热点商品缓存
refreshProductCache();
// 刷新活动缓存
refreshActivityCache();
}
}
```
## 缓存监控
### 缓存统计
```java
@Component
public class CacheMetricsService {
@Resource
private CacheManager cacheManager;
/**
* 获取缓存统计信息
*/
public Map<String, Object> getCacheStats() {
Map<String, Object> stats = new HashMap<>();
Collection<String> cacheNames = cacheManager.getCacheNames();
for (String cacheName : cacheNames) {
Cache cache = cacheManager.getCache(cacheName);
if (cache instanceof RedisCache) {
// 获取 Redis 缓存统计
stats.put(cacheName, getRedisCacheStats(cache));
}
}
return stats;
}
}
```
### 缓存健康检查
```java
@Component
public class CacheHealthIndicator extends AbstractHealthIndicator {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
try {
// 测试 Redis 连接
String pong = stringRedisTemplate.getConnectionFactory()
.getConnection().ping();
if ("PONG".equals(pong)) {
builder.up().withDetail("redis", "连接正常");
} else {
builder.down().withDetail("redis", "连接异常");
}
} catch (Exception e) {
builder.down().withException(e);
}
}
}
```
## 缓存优化策略
### 多级缓存
```java
@Service
public class MultiLevelCacheService {
@Resource
private CacheManager localCacheManager;
@Resource
private CacheManager redisCacheManager;
public <T> T get(String key, Class<T> type, Supplier<T> loader) {
// 1. 先查本地缓存
Cache localCache = localCacheManager.getCache("local");
T value = localCache.get(key, type);
if (value != null) {
return value;
}
// 2. 再查 Redis 缓存
Cache redisCache = redisCacheManager.getCache("redis");
value = redisCache.get(key, type);
if (value != null) {
// 回写本地缓存
localCache.put(key, value);
return value;
}
// 3. 最后查数据库
value = loader.get();
if (value != null) {
// 写入两级缓存
localCache.put(key, value);
redisCache.put(key, value);
}
return value;
}
}
```
### 缓存穿透防护
```java
@Service
public class BloomFilterService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 检查是否可能存在
*/
public boolean mightContain(String key) {
// 使用布隆过滤器检查
String bloomKey = "bloom:user";
return redisTemplate.opsForValue().getBit(bloomKey, hash(key));
}
/**
* 添加到布隆过滤器
*/
public void put(String key) {
String bloomKey = "bloom:user";
redisTemplate.opsForValue().setBit(bloomKey, hash(key), true);
}
private long hash(String key) {
// 简单的哈希算法
return Math.abs(key.hashCode()) % 1000000;
}
}
```
### 缓存雪崩防护
```java
@Service
public class AntiAvalancheService {
/**
* 随机过期时间防止雪崩
*/
@Cacheable(value = "user", key = "#id")
public UserDO getUser(Long id) {
// 缓存时间30分钟 + 随机0-10分钟
Duration timeout = Duration.ofMinutes(30 + new Random().nextInt(10));
UserDO user = userMapper.selectById(id);
// 手动设置过期时间
redisTemplate.expire("user:" + id, timeout);
return user;
}
}
```
## 最佳实践
### 缓存设计原则
1. **热点数据优先**: 经常访问的数据才缓存
2. **合理的过期时间**: 根据业务场景设置过期时间
3. **缓存键规范**: 使用有意义的键名和统一的命名规范
4. **避免大对象**: 单个缓存对象不要太大
5. **监控告警**: 设置缓存命中率等监控指标
### 常见问题解决
1. **缓存击穿**: 使用分布式锁保护热点数据
2. **缓存穿透**: 使用布隆过滤器或缓存空值
3. **缓存雪崩**: 设置随机过期时间
4. **数据一致性**: 使用缓存更新策略和事务
5. **内存泄漏**: 设置合理的过期时间和大小限制