缓存雪崩是大量key集中过期或Redis宕机导致的成片缓存失效,表现为Connection refused、expired_keys突增、keyspace_hits断崖下跌;击穿是单个热点key失效,穿透是大量异常key查询。

怎么确认是缓存雪崩而不是击穿或穿透?
先看错误现象:Connection refused 或 Timeout waiting for connection from pool 集中爆发,且日志里大量请求在 redis.get() 后立刻 fallback 到数据库查询——这不是单个 key 的问题,而是成片 key 同时 miss。再查 Redis 监控:如果 expired_keys 指标在某分钟内突增数千甚至上万,同时 keyspace_hits 断崖式下跌、keyspace_misses 暴涨,基本可锁定为雪崩。击穿只会体现在单个 hot key 的 get 请求陡增;穿透则伴随大量异常 key(如含特殊符号、负 ID、超长字符串)反复出现。
Redis 宕机导致的雪崩,第一步做什么?
别急着重启 Redis,先保数据库命:
- 立即触发熔断开关:检查是否有现成的
sentinel或Hystrix/Resilience4j熔断器,手动打开数据库访问的熔断开关,让非核心接口快速失败或返回兜底数据 - 临时降级缓存逻辑:在代码里绕过
redisTemplate.opsForValue().get(),直接走数据库(加限流),避免所有请求卡在 Redis 连接池等待 - 确认故障范围:用
redis-cli -h xxx -p xxx ping测试集群各节点;若主从全挂,检查systemctl status redis和磁盘、内存是否耗尽(df -h/free -h)
等数据库压力回落再恢复 Redis,否则一启动就会被压垮。
大量 key 集中过期怎么紧急止损?
不能等自然恢复,得主动干预:
- 用
redis-cli --scan --pattern "xxx:*" | xargs -L 1000 redis-cli expire {} 3600批量延长关键业务 key 的 TTL(注意:仅适用于未过期的 key;已过期的需重建) - 对刚过期的热 key,立刻用脚本批量预热:从数据库查出最新值,调用
redisTemplate.opsForValue().set()写入,TTL 加上随机偏移(比如基础 3600 秒 +random.nextInt(600)) - 禁止此时执行
flushall或全量del操作——这等于把雪崩从“局部”变成“全局”
临时措施只是止血,后续必须改写缓存设置逻辑,否则同一时间点还会复发。
为什么加随机过期时间后还是雪崩了?
常见坑点就三个:
-
baseTimeSeconds设得太小(比如统一设 60 秒),即使加了 ±300 秒随机,整体窗口也就 5 分钟,高并发下仍可能扎堆失效 - 用了
setex但没校验 key 是否已存在,旧 key 的过期时间没被覆盖,新写入的 key 反而提前过期 - 不同服务/模块各自 set 缓存,但没统一对齐随机策略(A 服务加 ±100 秒,B 服务加 ±20 秒),导致实际分布并不均匀
真正有效的随机化,得在统一缓存 SDK 层强制注入,而不是靠每个开发手写 random.nextInt()。


















