缓存毛刺本质是大量请求在毫秒级时间点集中穿透缓存,引发IO等待、连接争抢与线程阻塞;排查关键在于失效是否集中、可预测及是否导致级联延迟。

高并发下缓存失效瞬间出现响应时间毛刺,本质是大量请求在同一毫秒级时间点穿透缓存,集中打到下游(Redis 或 DB),引发 IO 等待、连接争抢、线程阻塞等连锁反应。排查关键不在于“有没有失效”,而在于“失效是否集中、是否可预测、是否引发级联延迟”。
一、确认毛刺是否真由缓存失效触发
先排除干扰项,聚焦缓存层行为:
- 查监控曲线:比对毛刺发生时刻的 QPS、缓存 miss rate、Redis 平均 RT、DB 连接池活跃数 —— 若三者同步陡升,大概率是缓存批量失效所致
- 看日志特征:在毛刺窗口内,是否密集出现 “cache miss”、“loading from db”、“set cache after load” 类日志,且 key 高度集中(如 user:1001、user:1002…连续编号)
- 检查缓存写入逻辑:回溯代码中 put 缓存的路径,确认是否对一批数据统一设置了相同 TTL(例如批量导入商品时全部设为 3600 秒)
二、定位失效集中点:从 Key 分布与过期策略入手
毛刺往往源于“时间维度上的强一致性”,而非数据本身问题:
- 用 Redis 命令扫描近期过期趋势:
redis-cli --scan --pattern "*"` + `ttl` 批量采样,或使用 <code>redis-cli info keyspace查各 db 的 key 数量变化节奏 - 检查是否使用了固定时间戳过期:比如用
EXPIREAT key 1726503840(某整点时间)代替EXPIRE key 3600,导致所有 key 在同一秒归零 - 确认是否有定时任务重刷缓存:如凌晨 2:00 全量刷新用户画像缓存,且未加随机偏移,造成整点雪崩
三、验证毛刺与网络/IO 的耦合关系
缓存失效本身不慢,慢的是后续动作 —— 这才是毛刺放大器:
- 测 Redis 单次 get 耗时:在毛刺前后分别执行
redis-cli --latency -h x.x.x.x,若 latency 从 0.8ms 涨至 15ms+,说明 Redis 已成瓶颈 - 抓取应用线程堆栈:在毛刺发生时用
jstack -l <pid>,观察是否大量线程卡在Jedis.get()、DataSource.getConnection()或数据库驱动的 socket read - 检查连接池配置:Druid/HikariCP 是否设置了合理 max-active / max-wait,是否存在连接耗尽后线程排队等待
四、快速验证与临时缓解手段
无需改代码,即可判断问题归属并稳住线上:
- 手动提前刷新一个疑似热点 key:
redis-cli set user:1001 "xxx" EX 3600,再压测该 key,观察毛刺是否消失 —— 若消失,说明是单 key 击穿;若仍存在,更倾向批量雪崩 - 临时关闭自动过期,改用主动刷新机制:停掉定时写缓存任务,改为后台线程每 30 分钟轮询更新热点 key,把“被动失效”转为“主动续命”
- 加一层本地缓存兜底:在应用内存中缓存最近 1000 个已查过的 key(哪怕只存 10 秒),让部分请求免走网络,削峰填谷


















