Files
loan-pricing/doc/2026-04-15-移除Redis依赖改造为内存缓存设计文档.md

7.2 KiB

移除 Redis 依赖改造为内存缓存设计文档

1. 背景

当前项目中 Redis 不仅用于通用缓存,还承担了以下业务能力:

  • 登录态缓存
  • 验证码缓存
  • 密码错误次数统计
  • 防重提交
  • 接口限流
  • 系统参数缓存
  • 数据字典缓存
  • 在线用户监控
  • 缓存监控页

本次改造目标是移除 Redis 依赖,并将以上依赖 Redis 的能力改造为基于单实例后端 JVM 内存的实现。

2. 设计约束

  • 后端部署模型明确为单实例
  • 不引入 Redis 兼容层、中间件替代品或额外持久化方案
  • 不引入 Caffeine、Guava 等新的缓存框架
  • 不改变现有业务 key 前缀和主要调用方式
  • 不做多实例共享、重启恢复、降级兜底等额外设计
  • 保留缓存监控功能,但改为展示内存缓存信息

3. 参考实现

本次设计参考 git 远端分支 origin/892-without-redis 的处理方向,但仅借鉴其“保留业务缓存入口、底层改为内存存储”的思路,不引入与当前 JDK 1.8 / Spring Boot 2 技术栈无关的框架升级改造。

4. 总体方案

4.1 核心思路

保留现有 com.ruoyi.common.core.redis.RedisCache 作为统一业务缓存入口,将其底层实现从 RedisTemplate 改为进程内缓存存储。

这样可以保证以下调用方的业务逻辑基本不变:

  • TokenService
  • SysLoginService
  • SysRegisterService
  • SysPasswordService
  • SameUrlDataInterceptor
  • SysConfigServiceImpl
  • DictUtils
  • SysUserOnlineController
  • CacheController

4.2 存储结构

ruoyi-common 中新增本地缓存存储组件,职责如下:

  • 使用 ConcurrentHashMap<String, CacheEntry> 保存缓存数据
  • CacheEntry 保存:
    • 实际缓存值 value
    • 过期时间戳 expireAtMillis
  • 读操作时判断是否过期
  • 过期数据在读取、扫描 key、统计快照时清理

4.3 保留的缓存门面能力

RedisCache 对外继续保留以下常用方法,以降低改造面:

  • setCacheObject
  • getCacheObject
  • deleteObject
  • hasKey
  • expire
  • getExpire
  • keys
  • setCacheMap
  • getCacheMap
  • setCacheMapValue
  • getCacheMapValue
  • setCacheList
  • getCacheList
  • setCacheSet
  • getCacheSet

另外补充两个内存实现需要的能力:

  • increment(key, timeout, unit):支持限流计数
  • getCacheStats():支持缓存监控页展示统计信息

5. 功能映射设计

5.1 登录态缓存

  • TokenService 继续使用 LOGIN_TOKEN_KEY + token 作为缓存 key
  • 登录成功时将 LoginUser 写入本地缓存,并设置与当前 token 配置一致的过期时间
  • 鉴权时仍通过 JWT 中的 token 标识查找缓存中的 LoginUser
  • token 临近过期时继续刷新本地缓存 TTL
  • 退出登录、强退用户时继续删除对应缓存 key

该设计保持当前认证链路不变,仅将状态存储位置从 Redis 改为 JVM 内存。

5.2 验证码缓存

  • CaptchaController 继续将验证码写入 CAPTCHA_CODE_KEY + uuid
  • TTL 保持分钟级
  • SysLoginServiceSysRegisterService 校验验证码后继续删除对应 key

5.3 密码错误次数统计

  • SysPasswordService 继续使用 PWD_ERR_CNT_KEY + username
  • 每次密码校验失败,错误次数自增并重置锁定窗口 TTL
  • 达到最大错误次数时维持现有异常行为
  • 登录成功后清理错误次数缓存

5.4 防重提交

  • SameUrlDataInterceptor 继续使用 REPEAT_SUBMIT_KEY + 请求地址 + token/header
  • 缓存值仍为请求参数快照和时间戳
  • TTL 继续使用注解 interval 指定的毫秒值
  • 比较逻辑不变,仍按“参数一致且时间窗口内重复提交”拦截

5.5 限流

  • RateLimiterAspect 删除对 RedisTemplate 和 Lua 脚本的依赖
  • 改为调用 RedisCache.increment(key, timeout, unit) 实现固定窗口内计数
  • 当计数值超过注解配置的阈值时,继续抛出当前业务异常

限流范围明确为当前单实例应用内,不做跨实例聚合。

5.6 系统参数缓存

  • SysConfigServiceImpl 保持现有 key 规则 SYS_CONFIG_KEY + configKey
  • 读取优先查本地缓存,未命中时查库并回填缓存
  • 新增、修改、删除、刷新操作保持现有清理逻辑

5.7 数据字典缓存

  • DictUtils 保持现有 key 规则 SYS_DICT_KEY + dictType
  • 字典写入、读取、删除、批量清理逻辑不变

5.8 在线用户

  • SysUserOnlineController 继续通过 LOGIN_TOKEN_KEY* 扫描缓存 key
  • 缓存中的 LoginUser 继续转换为在线用户列表
  • 强退用户仍通过删除指定 token key 实现

在线用户监控的可见范围定义为“当前单实例内未过期的登录 token”。

5.9 缓存监控

保留 /monitor/cache 相关接口和前端页面,但数据源改为本地缓存统计:

  • 缓存类型:IN_MEMORY
  • 运行模式:single-instance
  • 总键数
  • 命中次数
  • 未命中次数
  • 过期清理次数
  • 写入次数

同时保留以下能力:

  • 按缓存分类查看 key
  • 查看缓存值
  • 按分类清理缓存
  • 按 key 清理缓存
  • 清空全部缓存

6. 前端适配设计

本次前端改造仅针对缓存监控页,不扩展到其它模块。

6.1 缓存监控首页

页面保留原入口,但将 Redis 专属展示改为内存缓存语义:

  • Redis版本 改为 缓存类型
  • 运行模式 显示 单实例
  • dbSize 语义改为 总键数
  • 图表改为展示:
    • 命中次数
    • 未命中次数
    • 过期清理次数
    • 写入次数

6.2 缓存列表页

  • 保持现有接口路径和交互方式
  • 展示的数据仍按缓存 key 前缀分类
  • 支持查看值与清理操作

7. 依赖与配置调整

7.1 删除依赖

从 Maven 依赖中移除:

  • spring-boot-starter-data-redis
  • commons-pool2

7.2 删除配置

ruoyi-admin/src/main/resources/application.yml 中删除:

  • spring.redis 整段配置

7.3 删除基础设施代码

删除或停用以下 Redis 专属配置类:

  • RedisConfig
  • FastJson2JsonRedisSerializer

8. 兼容边界

以下行为是本次改造后的明确边界:

  • 服务重启后,登录态、验证码、限流计数、在线用户、密码错误次数等内存数据全部丢失
  • 缓存监控统计为当前进程内累计统计,不代表外部系统状态
  • 不支持多实例共享缓存

以上边界与“单实例后端”约束一致,属于本次设计的预期结果。

9. 测试与验收

9.1 后端测试重点

  • 本地缓存对象读写
  • TTL 过期行为
  • keys 模糊匹配
  • 删除和批量删除
  • 原子递增计数
  • token 登录态写入、读取、刷新、删除
  • 限流行为
  • 验证码写入与校验
  • 在线用户列表与强退
  • 系统参数缓存与字典缓存读取、刷新
  • 缓存监控接口返回结构

9.2 前端验收重点

  • 缓存监控页正常打开
  • 基本信息展示为内存缓存语义
  • 图表能正确展示内存统计数据
  • 缓存列表页能查看 key、查看值、清理缓存

10. 实施拆分

由于本次涉及后端与前端改造,实施阶段需要分别输出两份实施计划文档:

  • 后端实施计划
  • 前端实施计划

实施计划将在本设计确认后单独编写并保存到 doc/ 目录。