缓存失效后新内容未更新,关键在定位写入、传播、生效三环节断点:先查redis中key是否存在及ttl;再确认写入逻辑是否执行成功;接着排查cdn/nginx/浏览器等中间层拦截;最后检查redis内存淘汰与集中过期问题。

缓存失效后新内容没更新,不是“缓存丢了就完事了”,而是数据写入、传播、生效三个环节中某一处断开了。关键不在等它自动恢复,而在快速定位断点——是没写进去?写进去了但没传出去?还是传出去了但客户端/中间层还在用旧的?
第一步:确认新内容到底有没有进缓存
别猜,直接查。用 redis-cli 连上对应实例,对几个刚更新过的 key 执行:
- exists key_name → 返回 0 表示键根本不存在
- get key_name → 返回空字符串或 null,说明缓存了空值,不是失效,是误存
- ttl key_name → 返回 -2(不存在)、-1(永不过期)、正数(剩余秒数);若返回正数但数值极小(如 2~5 秒),说明刚设了很短过期时间
注意:别只查一个 key,挑 3~5 个高频更新的 key 批量验证,避免把个别 key 过期当成系统性延迟。
第二步:查写入动作是否真正发生
缓存没更新,大概率是代码里那行 set 或 setex 根本没执行成功。重点排查:
- 数据库更新成功了,但缓存删除/更新逻辑在事务外、被异常吞掉,或位于 if 分支里却没走到
- 用了异步更新(如发 MQ 消息),但消费者挂了、队列积压、重试失败未告警
- 缓存操作被 try-catch 吞异常,日志里只有 “update db success”,没记 “cache update fail”
- 多实例部署时,只有部分节点执行了更新(比如用了本地缓存 + Redis 混合,漏清本地)
建议在缓存写入前后加日志,格式统一为:[cache-write] key=xxx, value_size=1240, expire=3600, result=ok/error,便于 grep 追踪。
第三步:看中间层或客户端是否拦住了新内容
即使 Redis 里已有新值,用户看到的仍可能是旧的——因为 CDN、Nginx、浏览器层层拦截:
-
CDN 层:检查源站响应头是否含
Cache-Control: no-cache或max-age=0,这会让 CDN 强制不缓存;也可能是 CDN 自身 TTL 设得太长,新资源还没过期 -
Nginx 代理缓存:确认配置中没启用
proxy_cache,或已启用但没配proxy_cache_bypass和proxy_no_cache来绕过旧缓存 -
浏览器端:F12 查 Network → 点开请求 → 看 Response Headers 里的
Cache-Control和ETag/Last-Modified;若存在协商缓存头但服务端没正确响应 304,就会复用旧缓存
简单验证法:用 curl -I http://yoursite.com/path 绕过浏览器,看原始响应头;再换无痕窗口、禁用缓存模式访问,对比结果。
第四步:盯住淘汰与覆盖行为
Redis 本身可能“主动丢”新内容:
- 执行
info stats,看evicted_keys是否持续增长 → 内存不足触发淘汰,新 set 被踢出 - 看
expired_keys是否突增 → 大量 key 集中过期,造成雪崩式回源,新缓存来不及写入 - 执行
config get maxmemory-policy,若为noeviction且内存满,后续所有写操作会直接报错,缓存更新静默失败
此时要查业务代码里是否给所有 key 设置了相同过期时间(比如全设 1 小时),应改为加随机偏移(如 3600 + random(300))来分散过期压力。











