缓存用错能压垮数据库:穿透、雪崩与击穿的避坑指南
在前两期的内容中,我们探讨了缓存带来的性能提升优势。然而,缓存是一把双刃剑:配置得当可以显著提速,配置失误则可能导致数据库被瞬间压垮。
本期我们将深入剖析缓存使用中常见的三个致命陷阱:缓存穿透、缓存雪崩以及缓存击穿。理解这些问题的本质并掌握相应的解决策略,是构建高可用系统的关键。
``1. 缓存穿透 (Cache Penetration)
问题描述
正常的缓存查询流程是:先检查缓存,若命中则直接返回;若未命中,则查询数据库,并将结果存入缓存以备后续使用。
然而,当查询一个根本不存在的数据(例如一个不存在的用户 ID)时,会出现以下情况:
- 缓存中没有该数据。
- 数据库中也没有该数据。
- 由于没有有效数据,无法将其存入缓存。
- 下一次相同的请求到来时,依然会穿透缓存,直接查询数据库。
如果恶意用户利用大量不存在的 ID 进行高频请求,每一次请求都会直接打到数据库,导致数据库负载激增,甚至直接被打垮。
解决方案
缓存空值:当查询不到数据时,不要直接返回空,而是将“空值”或“特殊标记”存入缓存,并设置一个较短的过期时间(例如 1 分钟)。
这样,后续相同的请求会在缓存中命中这个空值,直接返回,从而避免了对数据库的无效查询。

2. 缓存雪崩 (Cache Avalanche)
问题描述
缓存雪崩是指系统中有大量缓存数据,且这些缓存的过期时间高度集中。当这些缓存同时过期时,下一秒所有的请求都会涌向数据库。
此时,数据库需要瞬间承受平时几十倍甚至上百倍的查询压力,极大概率会导致服务崩溃。
成因分析
最常见的原因是代码实现不规范,例如给所有缓存设置了统一的固定过期时间(如全部设为 30 分钟)。当批量写入的数据在 30 分钟后同时失效,就会引发雪崩。
解决方案
随机化过期时间:在设置缓存过期时间时,加入一个随机偏移量。
例如,基础过期时间为 30 分钟,可以在此基础上加减几分钟的随机值(如 28-32 分钟之间)。这样可以使不同缓存的过期时间错开,避免集中在同一时刻失效,从而平滑数据库的压力。

3. 缓存击穿 (Cache Breakdown)
问题描述
缓存击穿与雪崩类似,但影响范围更集中。它特指某一个特别热门的 Key(热点数据)在过期的一瞬间,大量并发请求同时到达。
由于缓存失效,这些请求会同时穿透到数据库,专门针对这一个查询造成巨大的压力,可能导致数据库连接池耗尽或查询超时。
解决方案
互斥锁重建:对热点 Key 加锁。
当缓存失效时,只允许一个请求去查询数据库并重建缓存,其他请求则等待该请求完成。一旦缓存重建成功,后续请求即可从缓存中获取数据。这种方式能有效保护数据库免受突发高并发的冲击。

总结
缓存穿透、雪崩和击穿,这三者的本质都是缓存未命中导致请求直接落到数据库。当请求量超过数据库的承载能力时,系统就会崩溃。
- 缓存穿透:查不存在的数据 -> 缓存空值。
- 缓存雪崩:大量缓存同时过期 -> 随机过期时间。
- 缓存击穿:热点 Key 过期 -> 加锁重建。

缓存加得好能提速,加不好能压垮整个系统。希望这些策略能帮助你避开常见的坑,构建更稳健的后端服务。