1. 缓存基础:概念、作用与三大经典问题

缓存是计算机科学中“以空间换时间”的经典策略。在搜索与 Redis 场景下,缓存的核心目标只有一个:让数据访问尽可能在内存中完成,避免穿透到数据库或磁盘。本章从最基础的概念出发,逐步建立对缓存穿透、击穿、雪崩的完整认知,为后续“闭环一致性”实战打下理论基础。

1.1 什么是缓存

缓存(Cache)是一层位于原始数据存储(如 MySQL、磁盘文件)与业务应用之间的临时数据副本层。它通常使用读写速度更快的存储介质(如内存),保存频繁访问的数据,从而降低响应延迟、减少后端负载。

核心特征:缓存中的数据是原始数据的“快照”,而非唯一来源。缓存与数据源之间必然存在一致性窗口——这是后续所有缓存一致性问题的根源。
对比维度 缓存层(Redis) 数据源(MySQL)
存储介质 内存 磁盘
读写延迟 微秒级(<1ms) 毫秒级(1~50ms)
数据容量 GB 级(受物理内存限制) TB 级
持久化 可选(RDB/AOF) 强持久化
一致性保证 最终一致性(默认) 强一致性(ACID)

1.2 缓存的作用

在搜索业务中,缓存承担三个关键角色:

  • 加速读请求:热门搜索词、商品详情、用户画像等高频数据,直接从 Redis 返回,响应时间从 50ms 降至 1ms 以内。
  • 保护后端系统:缓存层作为“防洪堤”,拦截 80%~90% 的读流量,防止数据库连接池被打满、磁盘 IO 过载。
  • 削峰填谷:秒杀、大促等流量尖峰场景下,缓存吸收瞬时冲击,避免系统雪崩。
经验数据:在搜索场景中,引入 Redis 缓存通常能将整体读接口的 TP99 延迟降低 10~20 倍,数据库 QPS 下降 70%~90%。

1.3 缓存穿透、击穿、雪崩:三大经典问题

这三个问题虽然名称相似,但成因、影响范围和解决方案截然不同。下表先做宏观对比,后续逐一展开。

问题 核心成因 影响范围 典型后果
缓存穿透 查询一个不存在的数据 单个 key 每次请求都穿透到数据库,导致 DB 压力骤增
缓存击穿 一个热点 key 在缓存中过期 单个热点 key 大量并发请求同时打到数据库,瞬间压垮 DB
缓存雪崩 大量 key 同时过期 或 Redis 宕机 大量 key / 整个缓存层 数据库被海量请求淹没,系统级故障

1.3.1 缓存穿透

当请求查询一个缓存和数据库中都不存在的数据时,缓存无法命中,每次请求都会穿透到数据库。攻击者可以利用这个漏洞,构造大量不存在的 key 进行恶意请求。

// 穿透场景:查询不存在的用户
GET /user/profile?id=-1
// 缓存未命中 → 查询 MySQL → 返回空 → 不写缓存
// 下一次请求 -1 依然穿透
典型危害:攻击者每秒发送 10000 个不存在的 ID,数据库需要承受 10000 QPS 的空查询,而正常用户请求反而被阻塞。

解决方案:

  • 缓存空对象:即使数据库返回空,也缓存一个短生命周期的 null 值(如 30s),避免重复穿透。
  • 布隆过滤器:在缓存前加一层 Bloom Filter,快速判断 key 是否存在,不存在则直接拒绝。
  • 参数校验:对非法参数(如负数 ID、超长字符串)在入口层直接拦截。

1.3.2 缓存击穿

一个热点 key(如“iPhone 16”搜索词、爆款商品详情)在缓存中过期失效的瞬间,大量并发请求同时涌入,全部穿透到数据库。

// 击穿场景:热点 key "hot_product_100" 过期
// 时间点 T:缓存过期
// 时间点 T+1ms:1000 个并发请求同时到达
// 1000 个请求全部未命中缓存 → 全部查询 MySQL

解决方案:

  • 互斥锁(Mutex):只允许一个线程去数据库加载数据,其他线程等待或重试。
  • 逻辑过期:缓存永不过期,但数据中携带过期时间字段,异步线程发现过期后主动更新。
  • 热点 key 不过期:结合定时任务主动刷新,避免被动过期。

1.3.3 缓存雪崩

缓存雪崩是三个问题中破坏力最大的。它有两种典型触发场景:

  1. 大量 key 同时过期:例如缓存预热时所有 key 设置了相同的过期时间(如 1 小时),到期瞬间所有 key 集体失效。
  2. Redis 实例宕机:整个缓存层不可用,所有请求直接落到数据库。
雪崩的连锁反应:数据库 QPS 从 1000 飙升到 100000 → 数据库连接池耗尽 → 请求排队超时 → 上游服务线程阻塞 → 整个调用链雪崩。

解决方案:

  • 过期时间加随机值:基础过期时间 + 随机 1~5 分钟,避免集体过期。
  • 多级缓存:本地缓存(Caffeine)+ 分布式缓存(Redis)分层防护。
  • Redis 高可用:主从 + Sentinel / Cluster,避免单点故障。
  • 限流降级:对数据库访问做限流,超出阈值直接返回降级数据或错误提示。

1.4 三大问题对比 SVG:成因与解决路径

缓存三大经典问题:成因与解决路径 缓存穿透 查询不存在的数据 解决方案 ① 缓存空对象(短TTL) ② 布隆过滤器前置拦截 ③ 参数合法性校验 缓存击穿 热点 key 过期瞬间 解决方案 ① 互斥锁(Mutex) ② 逻辑过期 + 异步刷新 ③ 热点 key 永不过期 缓存雪崩 大量 key 同时过期 / 宕机 解决方案 ① 过期时间加随机值 ② 多级缓存(本地+分布式) ③ Redis 高可用 + 限流 数据库(MySQL) 后果:DB 压力骤增 → 系统雪崩

1.5 缓存一致性:贯穿所有问题的核心

无论是穿透、击穿还是雪崩,最终都指向同一个本质问题:缓存与数据库之间的数据一致性如何保证?

  • 穿透:空值缓存策略本质上是在“缓存一个不存在的事实”,需要与数据库的写入操作保持协调。
  • 击穿:互斥锁方案在更新缓存时,需要确保并发环境下只有一个线程写入正确数据。
  • 雪崩:大量 key 重建时,如何保证每个 key 的缓存值与数据库值最终一致?