Redis 缓存雪崩的三个真实场景与应对
【摘要】 三个真实场景与对应的兜底策略。
Redis 缓存雪崩的三个真实场景与应对
先明确一件事
缓存雪崩不是"缓存挂了"这么简单。真正让服务崩掉的,是大量请求在缓存同时失效的瞬间全部打到数据库,数据库连接池被打满,超过恢复阈值之后即使缓存回来也救不动。这篇记录我在生产上遇到的三种情况,以及各自的处理方式。
场景一:整点批量预热,key 同时过期
运营活动在 0 点刷新榜单,几千个 key 的 TTL 都设成 24 小时,第二天 0 点整批失效。
处理方式很简单,把 TTL 打散:
import random ttl = 24 * 3600 + random.randint(-1800, 1800) redis.setex(key, ttl, value)
同一个 key 的过期时间落在半小时的窗口里,数据库压力被摊平,峰值下降约 70%。
场景二:热点 key 过期瞬间的击穿
单个热点 key 过期,几千 QPS 同时回源。这时候加互斥锁比打散 TTL 更有效:
def get_with_mutex(key):
val = redis.get(key)
if val is not None:
return val
if redis.set(f"lock:{key}", "1", nx=True, ex=3):
try:
val = load_from_db(key)
redis.setex(key, 600, val)
return val
finally:
redis.delete(f"lock:{key}")
for _ in range(50):
time.sleep(0.02)
val = redis.get(key)
if val is not None:
return val
return load_from_db(key)
注意最后那个兜底:锁等待超时后仍然回源,宁可多打一点数据库,也不要让请求卡死。
场景三:Redis 主从切换期间全量回源
这是最容易被忽略的。主库宕机,哨兵切换需要十几秒,这期间所有读请求 miss,直接压垮数据库。
两个手段:
• 本地进程内加一层很短的缓存(例如 200ms 的 LRU),能挡掉大部分重复读
• 降级开关:检测到 Redis 不可用时,读接口直接返回默认值或旧数据,不让流量穿透
监控指标
不要只盯 Redis 的命中率,真正有意义的是这几个:
• 数据库 QPS 的突增比例(超过基线 3 倍就告警)
• 应用侧连接池等待时间 P99
• 回源请求数 / 总请求数
小结
雪崩的根因永远是"瞬时并发 × 无缓存",所以解法也就三条:摊平时间、串行化回源、加一层更近的缓存。工程上最有效的往往不是最复杂的方案,而是把 TTL 加个随机数这么小的事。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)