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.
293 lines
13 KiB
293 lines
13 KiB
|
1 month ago
|
# 缓存策略
|
||
|
|
|
||
|
|
<cite>
|
||
|
|
**本文引用的文件**
|
||
|
|
- [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)
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
- [application.yml](file://crm-auth/src/main/resources/application.yml)
|
||
|
|
</cite>
|
||
|
|
|
||
|
|
## 目录
|
||
|
|
1. [简介](#简介)
|
||
|
|
2. [项目结构](#项目结构)
|
||
|
|
3. [核心组件](#核心组件)
|
||
|
|
4. [架构总览](#架构总览)
|
||
|
|
5. [详细组件分析](#详细组件分析)
|
||
|
|
6. [依赖关系分析](#依赖关系分析)
|
||
|
|
7. [性能考虑](#性能考虑)
|
||
|
|
8. [故障排查指南](#故障排查指南)
|
||
|
|
9. [结论](#结论)
|
||
|
|
10. [附录](#附录)
|
||
|
|
|
||
|
|
## 简介
|
||
|
|
本文件围绕CRM后端项目的缓存策略进行系统化说明,重点覆盖:
|
||
|
|
- Redis缓存配置与使用(连接池、序列化、集群模式)
|
||
|
|
- 常见缓存设计模式(Cache-Aside、Read-Through、Write-Through)的适用场景与实现要点
|
||
|
|
- 以 DeptTreeCache 为例,展示树形结构数据的缓存优化方案
|
||
|
|
- 缓存一致性保障(更新删除、失效时间、分布式锁等)
|
||
|
|
- 缓存监控、性能调优与故障恢复最佳实践
|
||
|
|
|
||
|
|
## 项目结构
|
||
|
|
本项目采用多模块组织,缓存相关能力主要分布在基础模块与认证模块中:
|
||
|
|
- crm-base:提供通用配置与工具,包含 Redis 配置类
|
||
|
|
- crm-auth:业务服务,包含部门树缓存实现与调用方
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph TB
|
||
|
|
subgraph "应用层"
|
||
|
|
APP["CrmAppApplication"]
|
||
|
|
AUTH_APP["AuthApplication"]
|
||
|
|
end
|
||
|
|
subgraph "基础模块 crm-base"
|
||
|
|
REDIS_CFG["RedisConfig<br/>Redis连接/序列化/集群配置"]
|
||
|
|
end
|
||
|
|
subgraph "认证模块 crm-auth"
|
||
|
|
DEPT_CACHE["DeptTreeCache<br/>部门树缓存封装"]
|
||
|
|
DEPT_SVC["SysDeptServiceImpl<br/>部门服务实现"]
|
||
|
|
end
|
||
|
|
subgraph "外部依赖"
|
||
|
|
REDIS["Redis 服务器/集群"]
|
||
|
|
DB["数据库(MyBatis-Plus)"]
|
||
|
|
end
|
||
|
|
APP --> AUTH_APP
|
||
|
|
AUTH_APP --> DEPT_SVC
|
||
|
|
DEPT_SVC --> DEPT_CACHE
|
||
|
|
DEPT_CACHE --> REDIS
|
||
|
|
DEPT_SVC --> DB
|
||
|
|
REDIS_CFG -.-> DEPT_CACHE
|
||
|
|
```
|
||
|
|
|
||
|
|
**图示来源**
|
||
|
|
- [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)
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
- [application.yml](file://crm-auth/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)
|
||
|
|
- [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
- [application.yml](file://crm-auth/src/main/resources/application.yml)
|
||
|
|
|
||
|
|
## 核心组件
|
||
|
|
- RedisConfig:集中管理Redis连接、序列化、超时、集群等关键参数,为上层缓存组件提供统一访问能力。
|
||
|
|
- DeptTreeCache:面向部门树的专用缓存封装,提供读路径优先、按需加载、批量构建与失效控制。
|
||
|
|
- SysDeptServiceImpl:部门数据服务,负责在写操作后触发缓存失效或重建,保证读写一致性。
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [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)
|
||
|
|
- [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"
|
||
|
|
participant DB as "数据库"
|
||
|
|
Note over Client,Service : "读路径(示例)"
|
||
|
|
Client->>Service : "查询部门树"
|
||
|
|
Service->>Cache : "getTree()"
|
||
|
|
alt "命中缓存"
|
||
|
|
Cache-->>Service : "返回树节点"
|
||
|
|
Service-->>Client : "返回结果"
|
||
|
|
else "未命中"
|
||
|
|
Cache->>DB : "加载根节点/全量数据"
|
||
|
|
DB-->>Cache : "原始数据"
|
||
|
|
Cache->>Redis : "序列化并写入"
|
||
|
|
Redis-->>Cache : "OK"
|
||
|
|
Cache-->>Service : "返回树节点"
|
||
|
|
Service-->>Client : "返回结果"
|
||
|
|
end
|
||
|
|
Note over Client,Service : "写路径(示例)"
|
||
|
|
Client->>Service : "修改部门信息"
|
||
|
|
Service->>DB : "持久化变更"
|
||
|
|
Service->>Cache : "invalidate()/refresh()"
|
||
|
|
Cache->>Redis : "删除/更新键"
|
||
|
|
Redis-->>Cache : "OK"
|
||
|
|
Service-->>Client : "返回成功"
|
||
|
|
```
|
||
|
|
|
||
|
|
**图示来源**
|
||
|
|
- [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)
|
||
|
|
|
||
|
|
## 详细组件分析
|
||
|
|
|
||
|
|
### Redis 配置与使用
|
||
|
|
- 连接池与超时:通过连接池参数控制最大连接数、空闲连接、获取超时等,避免连接耗尽与阻塞。
|
||
|
|
- 序列化策略:建议统一使用JSON序列化,确保跨语言兼容与可读性;对热点对象可考虑二进制压缩以提升吞吐。
|
||
|
|
- 集群模式:支持单机、哨兵与集群三种部署形态,需根据容量与可用性选择;集群模式下注意Key哈希槽分布与跨槽事务限制。
|
||
|
|
- Key命名规范:按“模块:实体:维度”分层,便于定位与批量清理;树形结构可采用“dept:tree:root”作为根键。
|
||
|
|
- 过期与淘汰:设置合理TTL并结合业务生命周期;热点数据可延长TTL,冷数据缩短TTL。
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
- [application.yml](file://crm-auth/src/main/resources/application.yml)
|
||
|
|
|
||
|
|
### 缓存设计模式
|
||
|
|
- Cache-Aside(旁路缓存)
|
||
|
|
- 适用场景:读多写少、允许短暂不一致、快速上线
|
||
|
|
- 实现要点:读时先查缓存,未命中再查库并回填;写时先更新库,再删除缓存
|
||
|
|
- 风险点:并发写导致脏读,可通过分布式锁或版本号解决
|
||
|
|
- Read-Through(读穿透)
|
||
|
|
- 适用场景:希望缓存层透明化,简化调用方逻辑
|
||
|
|
- 实现要点:缓存代理在缺失时自动从数据源加载并回填
|
||
|
|
- 风险点:数据源异常影响读取链路,需要降级与熔断
|
||
|
|
- Write-Through(写穿透)
|
||
|
|
- 适用场景:强一致要求高、写路径可控
|
||
|
|
- 实现要点:写时同步更新缓存与数据源,失败回滚
|
||
|
|
- 风险点:写延迟增加,需评估吞吐与一致性权衡
|
||
|
|
|
||
|
|
[本节为概念性内容,不直接分析具体文件]
|
||
|
|
|
||
|
|
### 树形结构缓存优化:DeptTreeCache
|
||
|
|
- 目标:将部门树结构整体缓存,减少重复组装与DB查询压力
|
||
|
|
- 数据结构:以根节点为键,子节点列表递归构建;必要时拆分“根键+子键集合”提升局部刷新效率
|
||
|
|
- 读路径:优先命中缓存,未命中则从DB加载并按层级拼装,最后落盘
|
||
|
|
- 写路径:部门增删改后,删除根键或局部子键,下次读时懒加载重建
|
||
|
|
- 并发控制:首次加载时使用分布式锁防击穿;热点更新使用短锁或版本号防雪崩
|
||
|
|
- 失效策略:基于事件驱动(写操作发布失效消息)或定时任务校验一致性
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
flowchart TD
|
||
|
|
Start(["进入 getTree"]) --> CheckCache["检查根键是否存在"]
|
||
|
|
CheckCache --> |存在| ReturnCache["返回缓存树"]
|
||
|
|
CheckCache --> |不存在| AcquireLock["尝试获取分布式锁"]
|
||
|
|
AcquireLock --> LockOk{"是否获得锁"}
|
||
|
|
LockOk --> |否| Fallback["等待或降级返回空/旧值"]
|
||
|
|
LockOk --> |是| LoadFromDB["从数据库加载部门数据"]
|
||
|
|
LoadFromDB --> BuildTree["构建部门树结构"]
|
||
|
|
BuildTree --> SaveCache["序列化并写入Redis"]
|
||
|
|
SaveCache --> ReleaseLock["释放分布式锁"]
|
||
|
|
ReleaseLock --> ReturnResult["返回树结构"]
|
||
|
|
Fallback --> End(["结束"])
|
||
|
|
ReturnCache --> End
|
||
|
|
ReturnResult --> End
|
||
|
|
```
|
||
|
|
|
||
|
|
**图示来源**
|
||
|
|
- [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
|
||
|
|
- 读接口:委托 DeptTreeCache 获取树结构,屏蔽底层细节
|
||
|
|
- 写接口:在完成数据库变更后,调用缓存失效或刷新方法,确保后续读路径能拿到最新数据
|
||
|
|
- 事务边界:写操作与缓存失效在同一事务内协调,避免中间态暴露
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant Client as "客户端"
|
||
|
|
participant Service as "SysDeptServiceImpl"
|
||
|
|
participant DB as "数据库"
|
||
|
|
participant Cache as "DeptTreeCache"
|
||
|
|
participant Redis as "Redis"
|
||
|
|
Client->>Service : "更新部门信息"
|
||
|
|
Service->>DB : "执行更新"
|
||
|
|
DB-->>Service : "返回成功"
|
||
|
|
Service->>Cache : "invalidateRoot()"
|
||
|
|
Cache->>Redis : "删除根键"
|
||
|
|
Redis-->>Cache : "OK"
|
||
|
|
Service-->>Client : "返回成功"
|
||
|
|
```
|
||
|
|
|
||
|
|
**图示来源**
|
||
|
|
- [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)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [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)
|
||
|
|
|
||
|
|
## 依赖关系分析
|
||
|
|
- 模块耦合
|
||
|
|
- DeptTreeCache 依赖 RedisConfig 提供的RedisTemplate/ConnectionFactory
|
||
|
|
- SysDeptServiceImpl 依赖 DeptTreeCache 与 MyBatis-Plus 数据访问层
|
||
|
|
- 外部依赖
|
||
|
|
- Redis:承担热点数据缓存与共享状态
|
||
|
|
- 数据库:权威数据源,缓存仅作为加速层
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph LR
|
||
|
|
Svc["SysDeptServiceImpl"] --> Cache["DeptTreeCache"]
|
||
|
|
Cache --> RedisCfg["RedisConfig"]
|
||
|
|
Cache --> RedisNode["Redis"]
|
||
|
|
Svc --> DB["数据库"]
|
||
|
|
```
|
||
|
|
|
||
|
|
**图示来源**
|
||
|
|
- [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)
|
||
|
|
- [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)
|
||
|
|
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
|
||
|
|
|
||
|
|
## 性能考虑
|
||
|
|
- 连接池调优
|
||
|
|
- 根据QPS与RT估算连接数,避免过大导致内存占用过高
|
||
|
|
- 调整获取连接超时,防止线程堆积
|
||
|
|
- 序列化优化
|
||
|
|
- 热点对象使用紧凑格式(如Protobuf/Kryo),非热点使用JSON
|
||
|
|
- 大对象分片存储,避免单次序列化开销过大
|
||
|
|
- 缓存粒度
|
||
|
|
- 树形结构可按层级拆分键,提高局部更新效率
|
||
|
|
- 热点键打散,避免单键过大
|
||
|
|
- 过期与预热
|
||
|
|
- 启动时预热常用树结构,降低冷启动冲击
|
||
|
|
- 动态TTL结合访问频率调整
|
||
|
|
- 集群与分片
|
||
|
|
- 关注Key哈希分布,避免热点槽
|
||
|
|
- 跨槽操作尽量规避,必要时拆分为多次请求
|
||
|
|
|
||
|
|
[本节为通用指导,不直接分析具体文件]
|
||
|
|
|
||
|
|
## 故障排查指南
|
||
|
|
- 常见问题
|
||
|
|
- 缓存穿透:空值缓存+布隆过滤器限流
|
||
|
|
- 缓存击穿:分布式锁保护首次加载
|
||
|
|
- 缓存雪崩:随机TTL+多级缓存
|
||
|
|
- 数据不一致:写后删/版本号/双写一致性校验
|
||
|
|
- 监控指标
|
||
|
|
- 命中率、平均RT、P99/P95、错误率、连接池使用率
|
||
|
|
- Redis内存、CPU、网络IO、慢查询日志
|
||
|
|
- 恢复策略
|
||
|
|
- 快速降级:关闭缓存直连DB
|
||
|
|
- 灰度发布:逐步放量新缓存策略
|
||
|
|
- 回滚机制:保留旧版本键与快照
|
||
|
|
|
||
|
|
[本节为通用指导,不直接分析具体文件]
|
||
|
|
|
||
|
|
## 结论
|
||
|
|
- 通过统一的Redis配置与规范的Key设计,奠定稳定高效的缓存基础
|
||
|
|
- 选择合适的缓存模式(Cache-Aside为主,必要时引入Read/Write-Through)平衡一致性与性能
|
||
|
|
- 针对树形结构采用专用缓存封装,显著提升读性能与可维护性
|
||
|
|
- 完善的一致性策略与监控体系,保障系统在高可用与高性能之间取得平衡
|
||
|
|
|
||
|
|
[本节为总结性内容,不直接分析具体文件]
|
||
|
|
|
||
|
|
## 附录
|
||
|
|
- 配置清单建议
|
||
|
|
- 连接池:最大连接数、空闲超时、获取超时
|
||
|
|
- 序列化:默认JSON,热点对象可选二进制
|
||
|
|
- 集群:节点地址、密码、超时、重试策略
|
||
|
|
- Key前缀:模块:实体:维度
|
||
|
|
- TTL:按业务设定,热点适当延长
|
||
|
|
- 代码片段路径
|
||
|
|
- Redis配置入口:[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)
|
||
|
|
- 服务集成点:[SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java)
|
||
|
|
- 应用配置:[application.yml](file://crm-app/src/main/resources/application.yml), [application.yml](file://crm-auth/src/main/resources/application.yml)
|