缓存是提升系统吞吐量最简单的手段,但它引入的问题也比你想象的更多。击穿、穿透、雪崩——这三个听起来像地质灾害的名词,是每一个高并发系统设计者必须跨越的三道坎。
缓存的基本模型
在深入三个核心问题之前,先建立一个标准的缓存读写模型:
标准缓存读取流程:
客户端 → 缓存层(Redis)→ [命中] → 直接返回
→ [未命中] → 数据库层 → 写入缓存 → 返回
标准缓存写入流程:
方案 A(Cache Aside):先更新数据库,再删除缓存
方案 B(Read/Write Through):通过缓存层代理读写
方案 C(Write Behind):只写缓存,异步刷入数据库
在绝大多数互联网场景中,Cache Aside(旁路缓存)是最常用的模式——代码直接操作 Redis 和数据库,简单透明。但正是这种简单性,隐藏着三大问题。
问题一:缓存穿透(Cache Penetration)
定义:查询一个根本不存在的数据,缓存中没有,数据库中也没有。每次请求都会穿透缓存直接打到数据库。
正常请求:
查询 user_id=123 → 缓存命中 → 返回(快)
穿透请求:
查询 user_id=-1 → 缓存未命中 → 查数据库 → 数据库也没有 → 返回空
查询 user_id=-1 → 缓存未命中 → 查数据库 → 数据库也没有 → 返回空
查询 user_id=-1 → 缓存未命中 → 查数据库 → 数据库也没有 → 返回空
如果每秒 10000 次这样的请求,数据库直接被压垮
穿透通常由恶意攻击或业务 Bug 引起——攻击者构造大量不存在的 ID,绕过缓存直接攻击数据库。