You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
336 lines
13 KiB
336 lines
13 KiB
|
1 month ago
|
# 缓存配置
|
||
|
|
|
||
|
|
<cite>
|
||
|
|
**本文引用的文件**
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
|
||
|
|
</cite>
|
||
|
|
|
||
|
|
## 目录
|
||
|
|
1. [简介](#简介)
|
||
|
|
2. [项目结构](#项目结构)
|
||
|
|
3. [核心组件](#核心组件)
|
||
|
|
4. [架构总览](#架构总览)
|
||
|
|
5. [详细组件分析](#详细组件分析)
|
||
|
|
6. [依赖关系分析](#依赖关系分析)
|
||
|
|
7. [性能考虑](#性能考虑)
|
||
|
|
8. [故障排查指南](#故障排查指南)
|
||
|
|
9. [结论](#结论)
|
||
|
|
10. [附录](#附录)
|
||
|
|
|
||
|
|
## 简介
|
||
|
|
本文件围绕项目的缓存配置与使用进行系统化说明,重点覆盖:
|
||
|
|
- Redis 连接与序列化配置要点
|
||
|
|
- 缓存注解的使用方式(如 @Cacheable/@CacheEvict)
|
||
|
|
- 自定义缓存组件实现(以部门树缓存为例)
|
||
|
|
- 缓存键设计策略、失效机制与穿透防护
|
||
|
|
- 性能优化建议、集群模式配置、监控与调试方法
|
||
|
|
|
||
|
|
## 项目结构
|
||
|
|
本项目采用多模块组织,缓存相关能力集中在基础模块的 Redis 配置中,业务模块通过服务层与自定义缓存组件进行使用。关键路径如下:
|
||
|
|
- 基础配置:RedisConfig.java
|
||
|
|
- 应用配置:application.yml
|
||
|
|
- 业务缓存:DeptTreeCache.java
|
||
|
|
- 业务服务:SysDeptServiceImpl.java
|
||
|
|
- 数据访问:SysDeptMapper.java
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph TB
|
||
|
|
subgraph "基础模块"
|
||
|
|
A["RedisConfig.java"]
|
||
|
|
end
|
||
|
|
subgraph "应用模块"
|
||
|
|
B["application.yml"]
|
||
|
|
end
|
||
|
|
subgraph "认证模块"
|
||
|
|
C["DeptTreeCache.java"]
|
||
|
|
D["SysDeptServiceImpl.java"]
|
||
|
|
E["SysDeptMapper.java"]
|
||
|
|
end
|
||
|
|
B --> A
|
||
|
|
D --> C
|
||
|
|
C --> A
|
||
|
|
D --> E
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
|
||
|
|
## 核心组件
|
||
|
|
- Redis 配置类:负责连接工厂、序列化器、模板装配等
|
||
|
|
- 应用配置文件:集中管理 Redis 连接参数、超时、序列化等
|
||
|
|
- 部门树缓存组件:封装部门树的读取、写入、失效与键生成逻辑
|
||
|
|
- 部门服务实现:在查询与更新时调用缓存组件,保证一致性
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
|
||
|
|
## 架构总览
|
||
|
|
下图展示了从请求进入服务层到缓存命中/回源再到数据库的完整流程,以及缓存失效时的更新路径。
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant Client as "客户端"
|
||
|
|
participant Service as "SysDeptServiceImpl"
|
||
|
|
participant Cache as "DeptTreeCache"
|
||
|
|
participant Redis as "Redis(由RedisTemplate操作)"
|
||
|
|
participant DB as "数据库(SysDeptMapper)"
|
||
|
|
Client->>Service : "获取部门树"
|
||
|
|
Service->>Cache : "getDeptTree()"
|
||
|
|
alt "缓存命中"
|
||
|
|
Cache-->>Service : "返回树结构"
|
||
|
|
Service-->>Client : "返回结果"
|
||
|
|
else "缓存未命中"
|
||
|
|
Cache->>DB : "查询根节点/全量数据"
|
||
|
|
DB-->>Cache : "原始数据"
|
||
|
|
Cache->>Redis : "序列化并写入缓存"
|
||
|
|
Cache-->>Service : "返回树结构"
|
||
|
|
Service-->>Client : "返回结果"
|
||
|
|
end
|
||
|
|
Note over Service,Cache : "当部门数据变更时,调用失效接口清理对应键"
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
|
||
|
|
## 详细组件分析
|
||
|
|
|
||
|
|
### Redis 连接与序列化配置
|
||
|
|
- 连接配置
|
||
|
|
- 通过 application.yml 提供主机、端口、密码、数据库索引、超时、连接池等参数
|
||
|
|
- RedisConfig 根据配置创建连接工厂、序列化器与 RedisTemplate
|
||
|
|
- 序列化配置
|
||
|
|
- 统一使用 JSON 序列化,确保跨语言与可读性
|
||
|
|
- 对 key/value 分别设置序列化器,避免类型不匹配导致的异常
|
||
|
|
- 模板装配
|
||
|
|
- 将 RedisTemplate 注入到需要缓存的业务组件中
|
||
|
|
- 为常用操作封装统一的读写方法,屏蔽底层细节
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
|
||
|
|
### 缓存注解使用
|
||
|
|
- 读缓存
|
||
|
|
- 使用 @Cacheable 标注在查询方法上,指定缓存名与键表达式
|
||
|
|
- 首次调用后结果写入缓存,后续相同参数直接命中
|
||
|
|
- 写缓存
|
||
|
|
- 使用 @CachePut 在更新方法上同步更新缓存值
|
||
|
|
- 删除缓存
|
||
|
|
- 使用 @CacheEvict 在删除或批量修改方法上清理缓存
|
||
|
|
- 条件缓存
|
||
|
|
- 通过 condition 与 unless 控制是否缓存及缓存条件
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
|
||
|
|
### 自定义缓存组件实现(部门树缓存)
|
||
|
|
- 职责划分
|
||
|
|
- DeptTreeCache 负责键生成、序列化、缓存读写与失效
|
||
|
|
- SysDeptServiceImpl 负责业务编排与事务边界
|
||
|
|
- 键设计
|
||
|
|
- 基于“业务前缀:实体:维度”原则,例如 dept:tree:all
|
||
|
|
- 支持按租户/环境隔离,避免键冲突
|
||
|
|
- 数据结构
|
||
|
|
- 部门树以对象或列表形式序列化存储,便于前端渲染
|
||
|
|
- 失效策略
|
||
|
|
- 部门增删改后主动失效对应键;必要时采用延迟双删或版本号策略
|
||
|
|
- 穿透防护
|
||
|
|
- 对空结果设置短 TTL 或布隆过滤器前置校验
|
||
|
|
- 热点键加互斥锁,避免并发击穿
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
flowchart TD
|
||
|
|
Start(["进入 getDeptTree"]) --> CheckCache["检查缓存键是否存在"]
|
||
|
|
CheckCache --> |存在| ReturnCache["反序列化并返回"]
|
||
|
|
CheckCache --> |不存在| QueryDB["查询数据库"]
|
||
|
|
QueryDB --> DataEmpty{"结果为空?"}
|
||
|
|
DataEmpty --> |是| SetNull["写入空值短TTL防穿透"]
|
||
|
|
DataEmpty --> |否| BuildTree["构建部门树结构"]
|
||
|
|
BuildTree --> Serialize["序列化并写入缓存"]
|
||
|
|
Serialize --> ReturnData["返回数据"]
|
||
|
|
SetNull --> ReturnNull["返回空结果"]
|
||
|
|
ReturnCache --> End(["结束"])
|
||
|
|
ReturnData --> End
|
||
|
|
ReturnNull --> End
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
|
||
|
|
### 缓存键设计策略
|
||
|
|
- 命名规范
|
||
|
|
- 统一前缀(如 crm:auth:dept:tree:all),包含系统、模块、实体与用途
|
||
|
|
- 维度隔离
|
||
|
|
- 加入租户、环境、版本等维度,避免共享污染
|
||
|
|
- 稳定性
|
||
|
|
- 键应稳定可预测,避免动态拼接导致无法定位问题
|
||
|
|
- 可观测性
|
||
|
|
- 键中包含必要标识,便于监控与排查
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
|
||
|
|
### 缓存失效机制
|
||
|
|
- 主动失效
|
||
|
|
- 在部门数据变更处调用失效接口,清理对应键
|
||
|
|
- 延迟双删
|
||
|
|
- 先删缓存,再更新数据库,最后再次删除缓存,降低不一致窗口
|
||
|
|
- 版本号/时间戳
|
||
|
|
- 在键中加入版本号或更新时间,配合读时校验
|
||
|
|
- 热点保护
|
||
|
|
- 对热点键加分布式锁或信号量,避免缓存击穿
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
|
||
|
|
### 缓存穿透防护
|
||
|
|
- 空值缓存
|
||
|
|
- 对查无数据的键设置较短 TTL,减少重复回源
|
||
|
|
- 布隆过滤器
|
||
|
|
- 在查询前用布隆过滤器判断是否存在,拦截非法 ID
|
||
|
|
- 限流与熔断
|
||
|
|
- 对异常流量进行限流,防止雪崩
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
|
||
|
|
## 依赖关系分析
|
||
|
|
- 组件耦合
|
||
|
|
- SysDeptServiceImpl 依赖 DeptTreeCache 完成缓存读写
|
||
|
|
- DeptTreeCache 依赖 RedisTemplate 进行持久化
|
||
|
|
- SysDeptMapper 提供数据源
|
||
|
|
- 外部依赖
|
||
|
|
- Redis 连接由 RedisConfig 装配,参数来自 application.yml
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
classDiagram
|
||
|
|
class SysDeptServiceImpl {
|
||
|
|
+获取部门树()
|
||
|
|
+更新部门()
|
||
|
|
+删除部门()
|
||
|
|
}
|
||
|
|
class DeptTreeCache {
|
||
|
|
+getDeptTree()
|
||
|
|
+evictDeptTree()
|
||
|
|
+buildKey()
|
||
|
|
}
|
||
|
|
class RedisTemplate {
|
||
|
|
+opsForValue()
|
||
|
|
+opsForHash()
|
||
|
|
+set(key,value,ttl)
|
||
|
|
+get(key)
|
||
|
|
}
|
||
|
|
class SysDeptMapper {
|
||
|
|
+selectDeptList()
|
||
|
|
+insertDept()
|
||
|
|
+updateDept()
|
||
|
|
+deleteDept()
|
||
|
|
}
|
||
|
|
SysDeptServiceImpl --> DeptTreeCache : "调用"
|
||
|
|
DeptTreeCache --> RedisTemplate : "使用"
|
||
|
|
SysDeptServiceImpl --> SysDeptMapper : "数据访问"
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
- [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java)
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
|
||
|
|
## 性能考虑
|
||
|
|
- 序列化开销
|
||
|
|
- 优先使用轻量级 JSON 序列化,避免大对象频繁序列化
|
||
|
|
- 连接池与超时
|
||
|
|
- 合理设置连接池大小、读写超时与重试次数
|
||
|
|
- 热点键与广播失效
|
||
|
|
- 热点键加本地缓存或分布式锁;批量失效采用增量策略
|
||
|
|
- 内存与过期
|
||
|
|
- 设置合理的 TTL,避免长期占用内存;定期清理无效键
|
||
|
|
- 网络与压缩
|
||
|
|
- 大对象启用压缩;尽量减小往返次数
|
||
|
|
|
||
|
|
[本节为通用指导,无需特定文件引用]
|
||
|
|
|
||
|
|
## 故障排查指南
|
||
|
|
- 连接失败
|
||
|
|
- 检查 application.yml 中的主机、端口、密码、SSL 与超时配置
|
||
|
|
- 确认 Redis 服务可达与防火墙策略
|
||
|
|
- 序列化异常
|
||
|
|
- 检查 RedisConfig 中 key/value 序列化器是否一致
|
||
|
|
- 确认实体类实现了必要的序列化接口
|
||
|
|
- 缓存未命中
|
||
|
|
- 核对键生成规则与调用方传入参数
|
||
|
|
- 查看 Redis 中是否存在对应键与 TTL
|
||
|
|
- 数据不一致
|
||
|
|
- 检查写路径是否执行了失效或双删
|
||
|
|
- 观察是否有并发更新导致竞态条件
|
||
|
|
- 监控与调试
|
||
|
|
- 开启 Redis 慢查询日志
|
||
|
|
- 增加缓存命中率统计与耗时埋点
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
|
||
|
|
|
||
|
|
## 结论
|
||
|
|
通过统一的 Redis 配置与规范的缓存组件设计,本项目实现了部门树的高效缓存与稳定的失效策略。建议在后续迭代中持续完善键设计与监控指标,结合集群部署与容量规划,进一步提升系统的可用性与性能。
|
||
|
|
|
||
|
|
[本节为总结性内容,无需特定文件引用]
|
||
|
|
|
||
|
|
## 附录
|
||
|
|
|
||
|
|
### 集群模式配置要点
|
||
|
|
- 连接模式
|
||
|
|
- 切换为集群模式,配置节点列表、密码与 SSL
|
||
|
|
- 序列化兼容性
|
||
|
|
- 确保所有节点使用一致的序列化器
|
||
|
|
- 路由与分区
|
||
|
|
- 关注哈希槽分布,避免热点键倾斜
|
||
|
|
- 高可用
|
||
|
|
- 启用主从复制与哨兵,设置合适的故障转移策略
|
||
|
|
|
||
|
|
[本节为通用指导,无需特定文件引用]
|
||
|
|
|
||
|
|
### 缓存监控与调试方法
|
||
|
|
- 指标采集
|
||
|
|
- 记录命中率、平均耗时、错误率与内存使用
|
||
|
|
- 可视化
|
||
|
|
- 接入监控系统展示趋势与告警
|
||
|
|
- 调试工具
|
||
|
|
- 使用 Redis CLI 查看键空间与 TTL
|
||
|
|
- 开启慢查询与日志级别调整
|
||
|
|
|
||
|
|
[本节为通用指导,无需特定文件引用]
|