Skip to content

Redis缓存设计

1. 这是什么

缓存设计是围绕 Redis 构建高性能读写链路的一套方法。
它不仅是“把数据放进去”,更包含过期、更新、一致性和高可用思考。

一句话理解:

  • 缓存不是简单副本
  • 它是数据库前面的一层带有时效性和风险控制的减压层

2. 为什么重要

缓存设计得好,系统吞吐和响应时间会明显改善。
设计不好,则会带来这些经典问题:

  • 缓存穿透
  • 缓存击穿
  • 缓存雪崩
  • 热点数据打爆数据库
  • 缓存和数据库不一致

所以缓存不是“加了就快”,而是要带着稳定性思维去设计。

3. 先建立直觉:缓存不是数据真相来源

学习缓存设计时,最重要的一条原则是:

  • 数据真相通常在数据库
  • 缓存更多是性能层和减压层

这意味着:

  • 你不能只关心命中率
  • 还要关心失效策略、更新策略、一致性兜底和异常流量

4. 核心内容

4.1 缓存穿透

缓存穿透指的是:

  • 请求的数据根本不存在
  • 缓存里没有
  • 数据库里也没有
  • 结果每次都直接打到数据库

常见应对:

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

4.2 缓存击穿

缓存击穿通常指:

  • 某个热点 key 失效了
  • 大量请求同时来查这个 key
  • 所有请求一起打到数据库

常见应对:

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

4.3 缓存雪崩

缓存雪崩通常指:

  • 大量 key 在同一时间集中失效
  • 大量请求一起穿透到数据库

常见应对:

  • 过期时间加随机值
  • 多级缓存
  • 限流降级
  • 热点数据提前预热

4.4 缓存一致性

缓存一致性是最重要、也最难完全做绝对强一致的部分之一。

常见思路包括:

  • 先更新数据库,再删除缓存
  • 先删缓存,再更新数据库
  • 延迟双删
  • 订阅 binlog / 消息异步更新缓存

学习阶段最重要的是先知道:

  • 一致性通常不是“自动拥有”
  • 它必须被设计出来

4.5 热点数据

热点数据的问题在于:

  • 访问集中
  • 瞬时并发高
  • 一个 key 就能成为系统瓶颈

常见处理思路:

  • 永不过期或逻辑过期
  • 本地缓存 + Redis 双层缓存
  • 热点 key 分片
  • 专项预热和限流

4.6 过期策略与淘汰策略

这两个概念容易混淆。

过期策略

关注的是:

  • 一个 key 到了 TTL 后怎么处理

淘汰策略

关注的是:

  • 内存不够时,Redis 要淘汰哪些 key

所以:

  • 过期是按时间
  • 淘汰是按容量压力

5. 学习重点

这一章最重要的是掌握:

  • 缓存是减压层,不是最终真相层
  • 穿透、击穿、雪崩是三种不同问题
  • 一致性设计永远是重点
  • 热点数据必须专项处理
  • 缓存方案必须结合访问特征和失败场景设计

6. 常见问题

6.1 只加缓存,不设计失效策略

这样早晚会遇到:

  • 数据脏
  • 热点失控
  • 难以排查

6.2 遇到一致性问题没有兜底手段

如果没有:

  • 重试
  • 延迟删除
  • 异步修正

一致性问题通常会反复出现。

6.3 热点数据没有专项处理

很多系统平时都正常,一到活动或流量峰值就崩,热点 key 往往是原因之一。

7. 一套最常用的缓存旁路思路

最常见的 Cache Aside 思路可以先这样记:

  1. 读请求先查缓存
  2. 缓存没有,再查数据库
  3. 查到后写入缓存
  4. 写请求先更新数据库
  5. 更新后删除缓存

这不是唯一方案,但它是最常见的起点。

8. 动手验证

当前环境没有 redis-cli,所以这篇我把重点放在“方案演练步骤”和“可复制命令”上。
如果你本地有 Redis,可以直接按下面做演练。

8.1 模拟缓存穿透

bash
GET user:999999

如果数据库里也没有这个用户,那么你应该思考:

  • 是否要缓存空值
  • 空值 TTL 多久合适

8.2 模拟缓存击穿设计思路

热点 key:

bash
GET product:1001

演练问题:

  • 如果这个 key 突然过期,同时 1 万个请求来查,谁去重建?
  • 是所有人一起查库,还是只有一个人查,其他人等待或降级?

8.3 模拟缓存雪崩设计思路

如果你批量设置缓存:

bash
SET item:1 v1 EX 600
SET item:2 v2 EX 600
SET item:3 v3 EX 600

那 600 秒后它们可能一起失效。
更好的做法往往是:

  • 在 TTL 基础上加随机偏移

例如设计成:

  • 600 ~ 660 秒随机过期

8.4 一致性方案演练

假设更新用户信息的流程是:

  1. 更新数据库
  2. 删除缓存 user:1

你应该重点思考:

  • 删除缓存失败怎么办
  • 数据库更新成功但缓存删除失败怎么办
  • 是否需要重试或异步补偿

9. 练习建议

下面这些练习做完,这一章会更扎实:

  • 设计一个缓存旁路方案
  • 模拟缓存击穿和雪崩场景
  • 总结缓存更新和失效的几种常见策略
  • 为热点 key 设计一套专项保护方案

10. 自测问题

  • 缓存穿透、击穿、雪崩的区别是什么?
  • 为什么缓存一致性永远是重点问题?
  • 热点数据为什么需要特殊处理?
  • 为什么缓存不是数据真相来源?
  • 过期策略和淘汰策略有什么区别?

11. 自测核对要点

如果你的回答能覆盖下面这些点,说明这一章基本掌握到位了:

  • 穿透是查不存在数据,击穿是热点 key 失效,雪崩是大量 key 集中过期
  • 缓存一致性需要显式设计,不能默认拥有
  • 热点数据会把单 key 问题放大成系统问题
  • 缓存方案要同时考虑命中率、更新、一致性和故障兜底
  • 过期和淘汰是两个不同维度的策略