缓存事故演练 / Cache stampede

一个 key 过期,为什么能拖垮商品库?

所有请求都命中了同一个热点接口。缓存刚好失效时,区别不在 Redis miss 本身,而在于随后究竟有多少请求同时拿着同一条 SQL 去抢数据库连接。

个
同一热点商品在 key 失效后收到的并发读取
ms
模拟 SELECT … FROM products WHERE sku = ?
条
无保护时,请求会在这里争抢连接

GET /products/sku-8848

起始状态:Redis 返回 nil,商品详情缓存不存在

等待选择一种模式 DB 0等待 0超时 0
HTTP 并发请求 Node.js
nil Redis miss key expired
POOL 连接池 排队取连接
SQL 商品数据库 products
200 响应 / 超时 1,000 ms

轨迹中的圆点是并发请求的代表样本;面板统计使用完整请求数。

两次运行的账单

P95 / P99 为客户端观察值,超过 1,000 ms 记为超时。

指标
无保护
互斥回填
数据库查询
未运行
未运行
服务端收尾
—
—
排队请求
—
—
客户端超时
—
—
P95 / P99
—
—
“排队请求”在无保护模式中指等待数据库连接,在互斥模式中指等待首个请求完成回填。真实系统还应给锁设置短 TTL,并在等待后重新读取 Redis,避免锁持有者异常退出造成永久阻塞。