Skip to content

缓存设计与一致性

1. 这是什么

缓存设计关注的是如何用 Redis 为系统减压,并在性能和一致性之间取得合理平衡。
它不是简单“把数据库结果放缓存里”这么直接。

一句话理解:

  • 缓存是数据库前的一层性能缓冲区
  • 它不是数据真相来源,而是性能和稳定性的权衡层

2. 为什么重要

缓存方案设计不好,系统不仅不会更快,还可能变得更难维护。
尤其在热点数据和高并发场景下,这些问题会非常突出:

  • 缓存穿透
  • 缓存击穿
  • 缓存雪崩
  • 数据不一致

3. 先建立直觉:缓存命中率高,不代表缓存设计就好

一个常见误区是:

  • 只盯命中率

但缓存设计真正要同时考虑的是:

  • 命中率
  • 一致性
  • 热点风险
  • 失效策略
  • 故障时的兜底路径

所以缓存不是“加上就好”,而是必须带着风险意识去设计。

4. 核心内容

4.1 缓存旁路模式

最常见的 Cache Aside 思路是:

  1. 先查缓存
  2. 没命中再查数据库
  3. 查到后回填缓存
  4. 更新时先改数据库,再删缓存

它不是唯一方案,但通常是学习和工程落地的起点。

4.2 缓存更新策略

常见设计包括:

  • 更新数据库后删除缓存
  • 更新数据库后同步更新缓存
  • 延迟双删
  • 通过消息或 binlog 异步刷新缓存

不同策略背后的本质问题都是:

  • 一致性代价怎么控制

4.3 缓存穿透

缓存穿透指:

  • 请求的数据根本不存在
  • 缓存没有
  • 数据库也没有
  • 所有请求都穿透到数据库

常见应对:

  • 缓存空值
  • 布隆过滤器
  • 参数校验

4.4 缓存击穿

缓存击穿通常指:

  • 某个热点 key 失效
  • 大量请求同时打到数据库

常见应对:

  • 互斥重建
  • 热点 key 永不过期或逻辑过期
  • 提前刷新

4.5 缓存雪崩

缓存雪崩通常指:

  • 大量 key 在同一时间失效
  • 数据库被瞬时流量冲击

常见应对:

  • TTL 加随机值
  • 多级缓存
  • 限流降级
  • 预热热点数据

4.6 热点数据治理

热点问题本质上是:

  • 单个 key 的访问被无限放大

常见处理:

  • 本地缓存 + Redis
  • 热点 key 分片
  • 单独保护热点链路
  • 热点数据预热

5. 学习重点

这一章最重要的是掌握:

  • 缓存不是数据真相来源
  • 穿透、击穿、雪崩是三种不同问题
  • 一致性永远是缓存设计的重点问题
  • 热点 key 需要专项治理

6. 常见问题

6.1 只考虑命中率,不考虑一致性

这样系统可能会很快,但会越来越不可信。

6.2 所有 key 同时过期

这是雪崩场景里最经典的错误之一。

6.3 热点 key 没有防护措施

热点问题往往不是平均流量能看出来的,而是在瞬时高峰暴露。

7. 动手验证

我已经验证过 Redis Docker 实验环境可用,你可以继续沿用:

bash
docker exec redis-lab redis-cli FLUSHALL

7.1 观察 TTL 与失效

bash
docker exec redis-lab redis-cli SETEX cache:item:1 5 value-1
docker exec redis-lab redis-cli TTL cache:item:1

这很适合体会:

  • 缓存并不是永久有效

7.2 设计“随机 TTL”演练

把同类 key 的 TTL 不要都写成同一个值,而是设计成:

  • 600 ~ 660 秒随机

例如在代码层做:

java
int ttl = 600 + random.nextInt(60);

7.3 穿透与空值缓存演练

bash
docker exec redis-lab redis-cli SETEX cache:user:404 60 NULL
docker exec redis-lab redis-cli GET cache:user:404

你会看到:

  • 即使数据库里没有这个用户,也可以用短 TTL 的空值挡掉反复穿透

8. 练习建议

  • 设计一个商品详情缓存方案
  • 模拟缓存击穿和雪崩场景
  • 总结不同一致性策略的优缺点
  • 为热点 key 设计专项保护方案

9. 自测问题

  • 缓存穿透、击穿、雪崩的区别是什么?
  • 为什么缓存一致性很难做到绝对完美?
  • 热点 key 应该怎样治理?
  • 为什么缓存命中率高不等于设计就一定合理?

10. 自测核对要点

  • 穿透是查不存在数据,击穿是热点 key 失效,雪崩是大量 key 集中过期
  • 一致性必须被设计出来,不能默认拥有
  • 热点 key 会把单点压力放大成系统压力
  • 缓存设计要同时考虑性能和稳定性