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.
 
 
 
 
 
 

13 KiB

缓存策略

**本文引用的文件** - [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)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件围绕CRM后端项目的缓存策略进行系统化说明,重点覆盖:

  • Redis缓存配置与使用(连接池、序列化、集群模式)
  • 常见缓存设计模式(Cache-Aside、Read-Through、Write-Through)的适用场景与实现要点
  • 以 DeptTreeCache 为例,展示树形结构数据的缓存优化方案
  • 缓存一致性保障(更新删除、失效时间、分布式锁等)
  • 缓存监控、性能调优与故障恢复最佳实践

项目结构

本项目采用多模块组织,缓存相关能力主要分布在基础模块与认证模块中:

  • crm-base:提供通用配置与工具,包含 Redis 配置类
  • crm-auth:业务服务,包含部门树缓存实现与调用方
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
  • DeptTreeCache.java
  • SysDeptServiceImpl.java
  • application.yml
  • application.yml

章节来源

  • RedisConfig.java
  • DeptTreeCache.java
  • SysDeptServiceImpl.java
  • application.yml
  • application.yml

核心组件

  • RedisConfig:集中管理Redis连接、序列化、超时、集群等关键参数,为上层缓存组件提供统一访问能力。
  • DeptTreeCache:面向部门树的专用缓存封装,提供读路径优先、按需加载、批量构建与失效控制。
  • SysDeptServiceImpl:部门数据服务,负责在写操作后触发缓存失效或重建,保证读写一致性。

章节来源

  • RedisConfig.java
  • DeptTreeCache.java
  • SysDeptServiceImpl.java

架构总览

下图展示了“服务-缓存-存储”的整体交互流程,以及不同缓存模式下的数据流向。

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
  • SysDeptServiceImpl.java

详细组件分析

Redis 配置与使用

  • 连接池与超时:通过连接池参数控制最大连接数、空闲连接、获取超时等,避免连接耗尽与阻塞。
  • 序列化策略:建议统一使用JSON序列化,确保跨语言兼容与可读性;对热点对象可考虑二进制压缩以提升吞吐。
  • 集群模式:支持单机、哨兵与集群三种部署形态,需根据容量与可用性选择;集群模式下注意Key哈希槽分布与跨槽事务限制。
  • Key命名规范:按“模块:实体:维度”分层,便于定位与批量清理;树形结构可采用“dept:tree:root”作为根键。
  • 过期与淘汰:设置合理TTL并结合业务生命周期;热点数据可延长TTL,冷数据缩短TTL。

章节来源

  • RedisConfig.java
  • application.yml
  • application.yml

缓存设计模式

  • Cache-Aside(旁路缓存)
    • 适用场景:读多写少、允许短暂不一致、快速上线
    • 实现要点:读时先查缓存,未命中再查库并回填;写时先更新库,再删除缓存
    • 风险点:并发写导致脏读,可通过分布式锁或版本号解决
  • Read-Through(读穿透)
    • 适用场景:希望缓存层透明化,简化调用方逻辑
    • 实现要点:缓存代理在缺失时自动从数据源加载并回填
    • 风险点:数据源异常影响读取链路,需要降级与熔断
  • Write-Through(写穿透)
    • 适用场景:强一致要求高、写路径可控
    • 实现要点:写时同步更新缓存与数据源,失败回滚
    • 风险点:写延迟增加,需评估吞吐与一致性权衡

[本节为概念性内容,不直接分析具体文件]

树形结构缓存优化:DeptTreeCache

  • 目标:将部门树结构整体缓存,减少重复组装与DB查询压力
  • 数据结构:以根节点为键,子节点列表递归构建;必要时拆分“根键+子键集合”提升局部刷新效率
  • 读路径:优先命中缓存,未命中则从DB加载并按层级拼装,最后落盘
  • 写路径:部门增删改后,删除根键或局部子键,下次读时懒加载重建
  • 并发控制:首次加载时使用分布式锁防击穿;热点更新使用短锁或版本号防雪崩
  • 失效策略:基于事件驱动(写操作发布失效消息)或定时任务校验一致性
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

章节来源

  • DeptTreeCache.java

服务层集成:SysDeptServiceImpl

  • 读接口:委托 DeptTreeCache 获取树结构,屏蔽底层细节
  • 写接口:在完成数据库变更后,调用缓存失效或刷新方法,确保后续读路径能拿到最新数据
  • 事务边界:写操作与缓存失效在同一事务内协调,避免中间态暴露
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
  • DeptTreeCache.java

章节来源

  • SysDeptServiceImpl.java
  • DeptTreeCache.java

依赖关系分析

  • 模块耦合
    • DeptTreeCache 依赖 RedisConfig 提供的RedisTemplate/ConnectionFactory
    • SysDeptServiceImpl 依赖 DeptTreeCache 与 MyBatis-Plus 数据访问层
  • 外部依赖
    • Redis:承担热点数据缓存与共享状态
    • 数据库:权威数据源,缓存仅作为加速层
graph LR
Svc["SysDeptServiceImpl"] --> Cache["DeptTreeCache"]
Cache --> RedisCfg["RedisConfig"]
Cache --> RedisNode["Redis"]
Svc --> DB["数据库"]

图示来源

  • SysDeptServiceImpl.java
  • DeptTreeCache.java
  • RedisConfig.java

章节来源

  • SysDeptServiceImpl.java
  • DeptTreeCache.java
  • 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
    • 树缓存封装:DeptTreeCache.java
    • 服务集成点:SysDeptServiceImpl.java
    • 应用配置:application.yml, application.yml