上周二上午9点,一家电商团队的结账系统突然503。数据库CPU飙到98%,缓存监控却一片绿色——问题恰恰出在缓存本身。14,000个并发请求同时撞上一张过期的产品页缓存,瞬间把Postgres打穿。这不是假设,是去年第四季度真实发生的8分钟事故。
这类场景有个专业名字:缓存踩踏(cache stampede)。更扎心的是,作者说"大多数团队栈里藏着全部四种漏洞,只是页面还没变红"。
一图看懂:踩踏的标准形状
先画清楚病灶长什么样。
缓存条目过期 → N个并发请求同时未命中 → 全部N个都去底层存储重建 → 存储按"缓存稳态负载"设计,扛不住N倍流量 → 服务崩溃。
最经典的触发条件:同步过期遇上热点key。邮件营销9点整推送,产品缓存TTL=3600秒,昨天8点部署时批量设置——最火的那款商品,所有Redis节点在同一秒把它踢出缓存。
作者提到"野外有充分文档记录的变体",但没展开列举。我们聚焦他给出的解法。
两道防线,必须一起用
第一招:TTL抖动(TTL jitter)。
给每个过期时间加个随机数。基础TTL设600秒,实际设置600 + random(0,60)。作者评价这是"你能做的最被低估的改动"——便宜,无需协调,把未命中曲线压平。
第二招:未命中时的单飞模式(single-flight on miss)。
一个请求去重建,其他请求等着读结果。实现上是个短生命周期的分布式锁带队列,不是硬互斥锁。
作者贴了一段Python代码演示核心逻辑:抢锁成功则重建并写缓存,失败则轮询等待(50毫秒间隔,5秒超时),最后兜底直接查库。
50毫秒轮询是刻意设计的——够短,让等待方在一轮往返内拿到新值;够长,避免疯狂spin Redis。5秒超时防止卡住整个连接池。
写穿缓存的陷阱
原文到这里被截断,但已暴露一个反直觉点:写穿缓存(write-through caching)的直觉是"缓存永远新鲜",但作者说"直觉在两条路径上都错了"——失败中途,以及绕过缓存的读。
具体哪两条路径,原文没给完整解释。我们能确认的是:同步写缓存+数据库的方案,并不像看起来那么安全。
为什么这事值得你今晚检查配置
缓存踩踏的阴险之处在于监控盲区。那个周二早晨,缓存健康、数据库挂掉——指标指向错误方向,团队花了8分钟才定位。
两招防御的成本极低:TTL抖动改几行配置;单飞模式有成熟实现(Redis的Redlock、Go的singleflight包)。作者没提具体框架,但代码片段已说明核心机制不复杂。
检查清单:你的热点key有没有集中过期时间?未命中重建有没有防重入机制?邮件/推送/定时任务的发送时间,是否恰好对齐了缓存TTL的整数倍?
别等页面变红才发现。
热门跟贴