缓存的价值是用更快、更便宜的读取换取有限时间的不一致风险。设计缓存前要先回答:缓存什么、允许旧多久、何时删除、失败时能否回源,以及热点失效时谁来重建。
Cache Aside 基本流程
读取:
1 | 读取 Redis |
更新常用做法:
1 | 更新数据库成功 -> 删除缓存 |
删除而不是直接更新缓存,可以减少多处业务同时维护复杂缓存结构的成本。下一次读取会从数据库重建。
为什么仍不是绝对一致
考虑这个竞态:
1 | 请求 A 缓存未命中,读到数据库旧值 |
所以“更新数据库再删缓存”只能降低不一致窗口。可结合短 TTL、版本号、延迟双删、消息失效通知或串行更新处理;强一致要求高的字段不应简单依赖旁路缓存。
穿透、击穿和雪崩
| 问题 | 发生方式 | 常见处理 |
|---|---|---|
| 穿透 | 持续查询根本不存在的数据 | 参数校验、空值短缓存、布隆过滤器 |
| 击穿 | 单个热点 Key 失效,大量请求同时回源 | 互斥重建、逻辑过期、热点预热 |
| 雪崩 | 大批 Key 同时失效或 Redis 整体不可用 | TTL 抖动、多级缓存、限流降级、高可用 |
空值缓存要设置较短 TTL,避免真实数据创建后仍长时间返回“不存在”。布隆过滤器可能误判存在,因此不能替代数据库校验。
热点 Key 的互斥重建
1 | 缓存未命中 |
释放锁时必须比较 token,避免误删已经被其他请求重新获得的锁。锁也要有过期时间,并为数据库失败准备降级路径。
不要缓存什么
- 访问很少且变化频繁的数据。
- 无法定义失效规则的关键状态。
- 超大对象或无边界列表。
- 高度敏感且缺少隔离措施的数据。
- 本来一次索引查询就足够快的数据。
监控指标
至少观察命中率、延迟、连接数、内存、驱逐数量、过期数量、热 Key、回源 QPS 和数据库耗时。命中率下降只是现象,还要判断是业务流量变化、TTL 设置、Key 设计还是 Redis 故障。