2. 缓存基础理论:缓存的作用与价值、常见缓存策略(LRU、LFU、TTL)、缓存穿透/击穿/雪崩
2.1 缓存的核心作用与业务价值
在 RBAC 权限系统中,缓存并非锦上添花,而是决定系统能否承载高并发访问的关键基础设施。权限数据的读取频率远高于写入频率,且每次鉴权都需要跨多个数据表(用户-角色-权限)进行关联查询,若直接压入数据库,系统会在极短时间内崩溃。
| 维度 | 无缓存场景(直接查库) | 有缓存场景(Redis / 本地缓存) |
|---|---|---|
| 单次鉴权延迟 | 10 ~ 50 ms(多表 JOIN) | 0.1 ~ 1 ms(内存读取) |
| 数据库 QPS 瓶颈 | 约 5,000 ~ 10,000 | 可支撑 100,000+(缓存扛量) |
| 热点数据压力 | 全部落在数据库 | 缓存吸收 95%+ 请求 |
| RBAC 典型场景 | 每次请求都查用户权限表 | 权限快照缓存,TTL 内零数据库查询 |
核心结论: 缓存的价值在于“用空间换时间”,将热数据从慢速存储(磁盘/数据库)提升到快速存储(内存),从而降低延迟、提升吞吐、保护后端数据库不被击穿。
2.2 常见缓存策略:LRU、LFU、TTL
缓存不是无限大的,当内存达到上限时,必须淘汰旧数据。不同的淘汰策略直接影响缓存命中率和系统行为。在 RBAC 水位复核中,我们最常与 LRU 和 TTL 打交道。
2.2.1 LRU(Least Recently Used)—— 最近最少使用
- 原理: 淘汰最长时间未被访问的数据。基于“时间局部性”假设:如果数据最近被访问过,未来被访问的概率也更高。
- 实现方式: 双向链表 + 哈希表(O(1) 查找与淘汰)。
- 适用场景: 用户会话缓存、通用数据缓存,访问模式有明显的热点变化。
- RBAC 场景: 适合缓存用户权限列表,因为活跃用户的权限会被频繁访问,而长期不活跃用户的权限自然被淘汰。
2.2.2 LFU(Least Frequently Used)—— 最不经常使用
- 原理: 淘汰访问频率最低的数据。基于“频率局部性”假设:访问次数多的数据未来更可能被再次访问。
- 实现方式: 维护每个 key 的访问计数器,淘汰时选择计数最小的 key。
- 适用场景: 热点数据相对固定、访问频率差异明显的场景。
- RBAC 场景: 适合缓存全局角色定义、权限码表等“几乎不变”的元数据。
2.2.3 TTL(Time To Live)—— 过期时间
- 原理: 为每个缓存 key 设置一个生存时间,到期后自动失效。这不是淘汰策略,而是数据一致性策略。
- 实现方式: Redis 的 EXPIRE 命令、本地缓存的定时扫描。
- 适用场景: 所有需要保证数据最终一致性的场景。
- RBAC 场景: 权限变更后,通过缩短 TTL 或主动失效来刷新缓存,避免用户持有过期权限。
| 策略 | 淘汰依据 | 内存开销 | RBAC 推荐用途 |
|---|---|---|---|
| LRU | 最后访问时间 | 中(链表指针) | 用户权限快照 |
| LFU | 访问频率 | 高(计数器) | 角色/权限元数据 |
| TTL | 时间 | 低(时间戳) | 所有缓存(配合使用) |
实战建议: 在 RBAC 缓存设计中,不要单独依赖 LRU 或 LFU。标准做法是:LRU + TTL 组合。LRU 控制内存水位,TTL 保证数据最终一致性。当权限发生变更时,优先使用主动失效(delete key),而不是等待 TTL 自然过期。
2.3 缓存三大经典问题:穿透、击穿、雪崩
这三个问题是缓存系统的“三大灾难”,在 RBAC 高并发鉴权场景中尤为致命。理解它们的成因和解决方案,是进行缓存水位复核的前提。
2.3.1 缓存穿透
- 定义: 请求查询一个根本不存在的数据(如一个不存在的用户 ID),缓存中没有,数据库也没有,每次请求都直接打到数据库。
- 危害: 恶意攻击者可以利用不存在的 key 发起大量请求,直接穿透缓存打垮数据库。
- 解决方案:
- 缓存空对象: 即使数据库查询为空,也缓存一个空值(如 null),并设置较短的 TTL(如 30~60 秒)。
- 布隆过滤器: 在缓存之前加一层布隆过滤器,判断 key 是否可能存在,不存在则直接拒绝。
2.3.2 缓存击穿
- 定义: 一个热点 key 在缓存失效的瞬间,大量并发请求同时涌入,全部穿透到数据库。
- 危害: 数据库瞬间被热点请求打爆,导致服务不可用。
- 解决方案:
- 互斥锁(Mutex): 只允许一个线程去数据库加载数据,其他线程等待或返回旧缓存。
- 逻辑过期: 缓存中不设置 TTL,而是存储一个逻辑过期时间,后台异步刷新。
- 永不过期 + 定时刷新: 热点 key 永不过期,由后台任务定期更新。
2.3.3 缓存雪崩
- 定义: 大量缓存 key 在同一时间集中过期,或者缓存节点宕机,导致大量请求直接打到数据库。
- 危害: 数据库压力瞬间飙升,可能引发级联故障,导致整个系统雪崩。
- 解决方案:
- TTL 随机化: 在基础 TTL 上增加一个随机偏移量(如 ±10%),避免集中过期。
- 缓存高可用: Redis 集群、哨兵模式,避免单点故障。
- 限流降级: 当缓存大面积失效时,对数据库请求进行限流,保护后端。
- 多级缓存: 本地缓存(Caffeine)+ 分布式缓存(Redis)组合,降低单层失效风险。
| 问题 | 根因 | 典型表现 | RBAC 场景举例 | 首选解决方案 |
|---|---|---|---|---|
| 穿透 | 查询不存在的数据 | DB 空查询激增 | 恶意遍历不存在的用户 ID | 布隆过滤器 + 空值缓存 |
| 击穿 | 热点 key 失效瞬间 | 单 key 打爆 DB | 超级管理员权限缓存失效 | 互斥锁 / 逻辑过期 |
| 雪崩 | 大量 key 同时失效 / 节点宕机 | DB 全面崩溃 | 所有角色缓存 TTL 同时到期 | TTL 随机化 + 多级缓存 |
⚠️ 水位复核重点关注: 在 RBAC 系统中,缓存雪崩是最容易被忽视的风险。很多团队只设置了统一的 TTL(如 3600 秒),导致所有权限缓存在同一秒过期。必须检查 TTL 是否添加了随机偏移,以及是否配置了本地缓存作为第二道防线。
2.4 本节小结
- 缓存的核心价值在于降低延迟、提升吞吐、保护数据库,在 RBAC 系统中是承载高并发鉴权的基石。
- LRU 适合用户权限快照,LFU 适合角色元数据,TTL 是所有缓存必须配合使用的数据一致性策略。
- 缓存三大问题——穿透、击穿、雪崩——在 RBAC 场景中都有对应的典型表现,必须通过布隆过滤器、互斥锁、TTL 随机化、多级缓存等手段进行系统性防御。
- 在后续的缓存水位复核中,我们将重点检查 TTL 配置是否合理、是否存在热点 key 集中过期、以及空值缓存是否被正确启用。