一次线上故障复盘:缓存击穿
本文目录
晚上八点,监控显示接口错误率突然上升,数据库连接数接近上限。排查后发现并非数据库故障,而是热点键在同一时刻过期,大量请求绕过缓存直接落到查询层。
现场处置顺序
第一步不是马上加机器,而是确认影响范围:哪些接口、哪些地区、是否所有用户都失败。随后临时延长热点键的过期时间,并在应用层加互斥锁,只允许一个请求回源。错误率在几分钟内回落,数据库连接也逐渐恢复。
if (!cache.has(key)) {
const value = await load(key);
await cache.set(key, value, ttl);
}
缓存失效不是异常,而是设计里必须被演练的常态。
- 热点键设置不同过期时间,避免同时失效。
- 回源加锁或合并请求,限制并发。
- 为缓存层准备降级开关。
- 故障结束后补监控与演练。
复盘时我们补了两件事:把热点键的过期时间打散,并在缓存客户端记录回源次数。前者减少同一时刻的失效,后者让问题在变成故障前就能被看见。
这次事故没有复杂的根因,问题在于默认缓存永远命中。只要接受它会失效,并提前设计好失效后的路径,很多连锁反应都可以被截断。所谓稳定性,往往就是把这些普通的分支认真写完。
另外,我们把这次处置写进了值班手册,明确谁有权调整缓存时间、何时升级告警。故障当下最耗时间的往往不是技术判断,而是确认谁来做决定。把权限和顺序提前写清楚,恢复速度会比想象中快。演练也要定期做,否则手册只会停留在纸面。