三大缓存问题
三大缓存问题是计算机系统中,特别是涉及缓存(Cache)技术时,最经典、最核心的三个典型问题。它们分别是:缓存穿透、缓存击穿和缓存雪崩。
这三个问题都可能导致大量请求直接落到后端数据库(如MySQL),造成数据库压力激增甚至崩溃,但其成因和解决方案各有不同。
下面我为你详细解释每一个问题。
1. 缓存穿透
问题描述:缓存穿透是指查询一个数据库中根本不存在的数据。由于缓存中也不会有这个数据(缓存未命中),导致这个请求每次都会“穿透”缓存层,直接去查询数据库。如果有人恶意构造大量这样的请求来攻击系统,数据库就可能不堪重负而宕机。
简单比喻:你想在学校图书馆(缓存)找一本《如何成为亿万富翁》,图书馆没有,于是你去国家总书库(数据库)找,发现这本书根本不存在。第二天你又来问同样的问题,这个流程又重复一遍。如果有成千上万的人每天都来问同一个不存在的问题,国家总书库的管理员就会忙到崩溃。
产生原因:
- 恶意攻击:攻击者故意请求大量不存在的数据ID(如负ID、超大ID或不存在的随机ID)。
- 业务代码bug:误删了数据,但前端仍在请求。
解决方案:
- 接口层增加校验:对请求参数进行合法性验证,例如对ID进行基础校验(ID<=0的直接拦截)。
- 缓存空对象:即使从数据库没查到,也将这个“空结果”(如
null
)进行缓存,并设置一个较短的过期时间(例如5分钟)。这样后续相同的请求在缓存失效前就能拿到结果,从而保护数据库。 - 使用布隆过滤器:在缓存和数据库之间加一道布隆过滤器。它是一个高效的数据结构,可以快速判断一个元素是否绝对不存在于某个集合中。系统在查询缓存前,先让布隆过滤器判断key是否存在: 如果判断为不存在,则直接返回空,无需查询缓存和数据库。如果判断为存在,则继续后面的缓存和数据库查询流程。注意:布隆过滤器判断“存在”时可能有误判,但判断“不存在”时是100%准确的,这正好适用于解决穿透问题。
2. 缓存击穿
问题描述:缓存击穿是指某一个热点数据(访问量非常大)在缓存过期的瞬间,同时有大量请求这个数据的请求到来。因为缓存刚刚失效,所有这些请求都会去数据库查询,并同时回写缓存,导致数据库瞬间压力过大。
简单比喻:一家超级网红店(热点数据)每天下午3点(缓存过期时间)会补货。3点整的时候,大门一开,成千上万的顾客(并发请求)瞬间涌入库房(数据库)抢购,差点把库房挤塌。
产生原因:
- 某个key是热点key,并发访问量非常大。
- 这个key在某个时间点恰好过期了。
解决方案:
- 设置热点数据永不过期:对极少数真正的顶级热点数据,可以设置其永不过期(逻辑过期),由后台服务异步地去更新它。
- 加互斥锁:在第一个请求发现缓存失效时,它先去获取一个分布式锁(如Redis的
SETNX
命令),然后才去查询数据库并回写缓存。在此期间,其他并发请求如果无法获取锁,则等待一小段时间后重试获取缓存。这样就只有一个线程能去访问数据库。 优点:保证数据库压力最小。缺点:用户体验上可能会有轻微延迟(等待锁)。
3. 缓存雪崩
问题描述:缓存雪崩是指在同一时间段内,大量的缓存数据集中过期失效,或者缓存服务(如Redis集群)直接宕机。导致所有原本应该访问缓存的请求全部涌向数据库,数据库压力骤增,甚至引发连锁反应导致整个系统崩溃。
简单比喻:双十一零点,所有商品的“限时优惠”标签(缓存数据)在同一瞬间全部消失(缓存集中过期)。所有想查看优惠的顾客(请求)都涌向后台客服(数据库)询问,客服电话瞬间被打爆,系统瘫痪。
产生原因:
- 大量key设置了相同的过期时间:这是最常见的原因,比如在初始化数据时,批量写入缓存并设置了相同的TTL(生存时间)。
- Redis服务宕机:缓存层整体不可用。
解决方案:
- 错开过期时间:给缓存数据的过期时间加上一个随机值(例如,基础时间 + 随机1-5分钟),让key的失效时间点尽量均匀分布,避免大量key同时失效。
- 构建高可用的缓存集群:通过Redis哨兵(Sentinel)或集群(Cluster)模式,实现缓存服务的高可用,防止因单点故障导致整个缓存层宕机。
- 服务降级和熔断:在系统检测到数据库压力过大时,可以采用服务降级策略,比如直接返回预定义的默认信息、空值或错误页面,保护数据库不被拖垮。使用Hystrix等工具实现熔断。
- 提前预热:在系统高峰来临前(例如电商大促前),提前加载热点数据到缓存中,并设置好错开的过期时间。
总结对比
缓存穿透 | 查询 不存在 的数据 | 恶意攻击、业务bug | 参数校验、缓存空对象、布隆过滤器 |
缓存击穿 | 单个热点key 过期时的高并发访问 | 热点key在某个时间点过期 | 设置永不过期、加互斥锁 |
缓存雪崩 | 大量key 同时过期 或 缓存服务宕机 | 设置了相同的过期时间、Redis节点宕机 | 错开过期时间、构建高可用集群、服务降级与熔断 |
理解这三大问题的区别和各自的解决方案,是设计和维护一个高可用、高性能系统的必备知识。