Files
loan-pricing/doc/2026-03-28-remove-redis-design.md

279 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 生产环境移除 Redis 依赖设计文档
## 1. 背景
当前项目基于若依前后端分离架构Redis 在系统中承担了多类运行时状态能力,包括:
- JWT 登录态缓存
- 验证码缓存
- 登录失败次数缓存
- 防重提交短期缓存
- 接口限流计数
- 系统配置缓存
- 数据字典缓存
- 在线用户查询与强退
- 缓存监控页面与缓存清理接口
现有生产环境没有 Redis因此需要彻底移除 Redis 依赖,并保证修改后与修改前的业务功能保持一致。
## 2. 已确认约束
- 生产环境为单实例部署
- 应用重启后,登录态、验证码、限流计数、登录失败次数等临时状态允许丢失
- 不引入新的中间件
- 不额外设计数据库持久化方案
- 目标是最短路径实现,避免补丁式和过度设计方案
## 3. 目标
- 移除 Redis 运行依赖与相关配置
- 保留现有业务功能与主要接口行为
- 保留现有前端缓存监控入口与主要能力
- 保证项目在无 Redis 配置、无 Redis 服务的情况下可正常启动和运行
## 4. 方案对比
### 方案一:统一进程内缓存层替换 Redis
将当前基于 Redis 的缓存访问统一收口为进程内缓存实现,保持上层业务调用方式和缓存语义尽量不变。
优点:
- 改动集中,替换边界清晰
- 最容易保持原有业务行为不变
- 不需要引入新基础设施
- 适合单实例部署场景
缺点:
- 需要补足 TTL、前缀查询、统计信息等基础能力
- 限流逻辑需要从 Redis 脚本改为本地原子实现
### 方案二:按场景分别重写
登录态、验证码、配置缓存、字典缓存、限流、防重分别改造成各自独立的本地实现。
优点:
- 单点改造直观
缺点:
- 改动分散
- 行为一致性难保证
- 容易遗漏使用点
- 后续维护成本更高
### 方案三:部分状态改存数据库
将登录态、验证码、失败次数等状态迁移到 MySQL。
优点:
- 状态具备一定持久性
缺点:
- 偏离本次最短路径目标
- 需要新增表结构、清理逻辑和一致性处理
- 复杂度明显高于当前需求
## 5. 设计结论
采用方案一:以统一进程内缓存层替换 Redis。
实现原则:
- 保留当前主要业务调用入口,避免业务层大面积改写
- 将所有 Redis 依赖集中替换为本地线程安全缓存实现
- 保持 key 组织方式、TTL 语义、按前缀检索、删除和清理行为不变
- 对外接口路径尽量不变,优先保障现有前后端功能连续性
## 6. 总体设计
### 6.1 基础设施替换边界
本次改造不采用“逐处删除 Redis 调用”的方式,而是保留当前缓存入口职责,将底层从 Spring Data Redis 替换为进程内缓存服务。
范围包括:
- 移除 `spring-boot-starter-data-redis` 依赖
- 移除 `application-*.yml` 中的 Redis 配置
- 移除 `RedisTemplate``RedisConnectionFactory`、Lua 限流脚本等 Redis 专属配置
- 为现有缓存访问入口提供本地实现
### 6.2 本地缓存能力要求
本地缓存组件必须提供以下能力:
- `set`
- `get`
- `hasKey`
- `delete`
- 批量删除
- 基于前缀的 `keys(pattern*)`
- TTL 过期控制
- 过期数据清理
- 基础命中和访问统计
该缓存实现需要线程安全,以保证登录、限流、防重提交等高频路径在单实例下的正确性。
## 7. 业务行为兼容设计
### 7.1 登录态
`TokenService` 当前通过 JWT 保存 token 标识,并将 `LoginUser` 存入 Redis。改造后继续维持该模型
- JWT 内容保持不变
- `token -> LoginUser` 存入本地缓存
- TTL 仍由 `token.expireTime` 控制
- 临近过期时继续自动续期
- 注销时删除对应登录态
这样可以保持登录、鉴权、刷新 token、在线用户列表、强退用户等行为不变。
### 7.2 验证码
验证码继续按 `uuid -> code` 存储在本地缓存中,并沿用当前过期时间配置。
- 生成验证码后写入缓存
- 校验时读取并删除
- 过期后自动失效
### 7.3 登录失败次数
登录失败次数继续按用户名缓存,保持:
- 连续失败次数累加
- 达到阈值后锁定
- 锁定时间到期后自动解除
- 登录成功后清理失败记录
### 7.4 防重提交
`SameUrlDataInterceptor` 继续按 `url + submitKey` 保存短时缓存,保留当前毫秒级过期控制和重复提交判断逻辑。
### 7.5 限流
原有限流逻辑依赖 Redis Lua 脚本做原子计数。由于当前部署为单实例,可以改为本地原子计数实现,保留现有注解参数语义:
- 限流 key 规则不变
- 时间窗口含义不变
- 阈值含义不变
- 超限返回逻辑不变
### 7.6 系统配置缓存
`SysConfigServiceImpl` 继续通过缓存保存系统配置,保持:
- 启动加载缓存
- 按 key 读取缓存
- 新增、修改、删除配置时同步刷新缓存
- 手动刷新缓存接口继续可用
### 7.7 数据字典缓存
`DictUtils` 与字典服务继续使用缓存保存字典数据,保持:
- 首次加载与重载逻辑不变
- 字典刷新接口不变
- 前端字典相关功能无感知
### 7.8 在线用户
在线用户列表和强退功能继续基于登录 token 前缀扫描实现,因此本地缓存必须支持按前缀查询 key。
### 7.9 缓存监控
不删除缓存监控功能。保留:
- 菜单入口
- 前端页面路由
- 后端接口路径
- 缓存清理能力
底层统计来源从 Redis 改为本地缓存统计视图。
## 8. 缓存监控设计
### 8.1 保留现有能力
`CacheController` 继续提供以下接口能力:
- 缓存概览
- 缓存名称列表
- 指定分类下的 key 列表
- 指定 key 的值查看
- 按分类清理
- 按 key 清理
- 全量清理
### 8.2 监控数据来源调整
由于 Redis 已移除,缓存监控页面中的信息调整为本地缓存统计信息,例如:
- 缓存类型:`IN_MEMORY`
- 运行模式:`single-instance`
- 当前缓存总数
- 读取次数
- 命中次数
- 过期清理次数
返回结构应尽量兼容当前前端页面,减少前端改动范围。
### 8.3 文案调整
对于前端页面中明显写死的 Redis 文案,需要调整为更准确的“缓存监控”或“本地缓存监控”,避免出现界面语义错误。
## 9. 配置与依赖调整
需要完成以下调整:
- 删除 Maven 中 Redis 相关依赖
- 删除后端配置中的 Redis 段
- 清理 Redis 专属配置类与序列化器引用
- 清理直接依赖 `RedisTemplate` 的控制器和切面实现
- 将相关逻辑改为依赖统一的本地缓存服务
## 10. 测试与验收
验收以业务行为为准,至少覆盖:
- 登录成功后可访问受保护接口
- token 临近过期时自动续期正常
- 在线用户列表可查询
- 在线用户强退可用
- 验证码生成与校验正常
- 登录失败次数限制正常
- 防重提交正常
- 限流正常
- 配置缓存刷新正常
- 字典缓存刷新正常
- 缓存监控页面可打开、可查看、可清理
- 项目在无 Redis 配置、无 Redis 服务时可启动
## 11. 风险与边界
- 本方案仅适用于当前确认的单实例部署
- 由于缓存改为进程内存储,多实例部署时不会共享状态
- 重启后临时状态会丢失,此行为已被确认可接受
- 本次不增加跨实例一致性能力,不增加持久化方案
## 12. 实施范围说明
本设计文档仅定义 Redis 移除与本地缓存替换方案,不扩展到以下范围:
- 多实例一致性方案
- 引入数据库持久化缓存
- 引入新的第三方缓存组件
- 额外新增降级或兜底机制
## 13. 后续输出
在该设计确认后,下一步需要输出两份实施计划:
- 后端实施计划
- 前端实施计划
并在实际编码改动时同步维护对应实施记录文档。