关于91大事件,我把缓存管理讲清楚后,很多问题都通了(别被误导)

简介 当“91大事件”翻来覆去被讨论时,真正的根源往往不是单一 bug,而是缓存管理的混乱。缓存既能带来惊人的性能提升,也能放大错误、制造数据不一致和安全隐患。把缓存机制、策略和常见误区讲清楚后,很多看似复杂的问题瞬间变得可控。下面是我多年实战总结,直截了当、可执行的缓存管理指南——用于修复问题、避免再犯,并提升系统稳定性与可观测性。
一、先说核心观念(几句话能看懂)
- 缓存是权衡:性能和一致性、复杂性之间的折中。
- 明确缓存边界:哪些数据可以长期缓存、哪些不能缓存、什么时候采用短 TTL 或强制失效。
- 缓存策略要可测、可验证、可回滚。
二、常见误区(别被误导)
- “清浏览器缓存就能解决所有问题” —— 只对客户端静态资源临时有效,无法修复后端缓存冲突或数据泄露。
- “长 TTL = 永久加速” —— 静态资源可以,但动态、敏感数据必须用版本化或短 TTL,否则会造成脏读或隐私泄露。
- “CDN 装上去后就万无一失” —— CDN 只是传输层缓存,origin 配置、Cache-Control、Vary、cache key 才是决定因素。
- “ETag/Last-Modified 就够了” —— 条件请求减少数据量,但不等于正确的业务缓存策略;并发失效、缓存风暴问题还需别的手段。
三、实战要点(最容易出问题的地方) 1) Cache key 与隔离
- 明确缓存 key 的组成:protocol、host、path、query(是否包含)、必要的 header(如 Accept-Encoding)。错误的 key 会造成用户 A 的数据被用户 B 看到(多租户灾难)。
- 对于多租户/多用户场景,强制在 key 中包含 tenantId/userId(如果缓存的是用户特定数据,通常不应缓存到公共 CDN)。
2) 静态资源:版本化 + 长缓存
- 对不可变资源使用文件名指纹(hash):app.a1b2c3.js,配合 Cache-Control: public, max-age=31536000, immutable。
- 不要用短 TTL 去“解决”旧版本问题,版本化比清缓存可靠得多。
3) 动态 API:短 TTL / 协商缓存 / 缓存分层
- 对需要实时性的 API,使用 Cache-Control: max-age=0, must-revalidate 或 no-cache;对可容忍短暂过期的场景,可用 stale-while-revalidate。
- 考虑边缘缓存 + origin cache(CDN + Redis 层):读多写少的场景可在边缘设较短的 TTL,写操作回源并主动使相关 key 失效或变更版本号。
4) Cache-Control 指令实例
- 静态不可变:Cache-Control: public, max-age=31536000, immutable
- 可短期缓存但需及时刷新:Cache-Control: public, max-age=60, stale-while-revalidate=30, stale-if-error=86400
- 敏感/动态:Cache-Control: private, no-store 或 no-cache, must-revalidate
5) 条件请求(ETag/Last-Modified)
- 用于减少带宽和加速但注意生成成本:ETag 生成必须稳定且高效;对集群要确保一致(避免不同实例生成不同 ETag 导致无谓回源)。
- 条件请求不会解决缓存一致性问题,只能优化流量。
6) 缓存失效与缓存击穿、雪崩、穿透
- 缓存穿透:对不存在的数据大量请求 -> 前端/防火墙层加校验或布隆过滤器。
- 缓存击穿:热点 key 到期时大量并发请求 -> 使用互斥锁、单飞(single-flight)或提前刷新(预热/延长随机 TTL)。
- 缓存雪崩:大量 key 同时过期 -> 使用 TTL 随机化、分散失效时间、或逐步回滚部署。
7) 缓存清除机制:版本化优先于手动清除
- 优先采用版本化(改变 URL)来保证客户端能拿到最新资源,减少大规模清除带来的风险。
- CDN 清理(purge)作为补救手段:要小心滥用,可能导致瞬时 origin 压力上升。清理前做好流量管控和回滚计划。
8) 安全与隐私
- 不要将用户敏感信息放在 public 缓存中。对用户相关响应使用 Cache-Control: private 或完全禁止缓存。
- 对 API 返回的错误页面或重定向特别小心,有时会被缓存成统一错误状态。
四、可观测性与回滚策略
- 必备指标:cache hit ratio(整体与按 endpoint)、origin 请求量、latency P50/P95/P99、error rate、CDN purge 次数。
- 部署新策略先在小流量灰度,观察 hit ratio 和 origin load,再扩大比例。出现问题可立刻回滚到上一个版本或调整 TTL。
五、常见故障排查流程(遇到用户抱怨:内容没更新 / 数据错乱) 1) 确认是哪个层被缓存(浏览器/CDN/边缘缓存/应用缓存/数据库缓存)。 2) 检查响应头(Cache-Control、Expires、ETag、Vary、Set-Cookie 等)。 3) 查看缓存 key 是否包含不应包含的标识(如公共 key 却混入 userId)。 4) 若为静态资源问题,优先查看文件是否版本化;若没有,考虑发布策略失败。 5) 若为 API 数据不一致,检查是否有写入后未触发失效、或多层缓存未同步。 6) 若 Origin 突然被打爆,可能是 purge 后没做流量平滑,检查是否需要限流或降级策略。
六、立即可用的 10 项行动清单(落地即用)
- 为静态资源加文件指纹,配合长 TTL + immutable。
- 对用户敏感响应设置 Cache-Control: private 或 no-store。
- 对热点 API 采用缓存分层(CDN + Redis)并设置合理 TTL。
- 为关键缓存 key 引入版本号,避免全局 purge。
- 在部署前预热 CDN/缓存,减少冷启动流量。
- 设置并监控 cache hit ratio 与 origin qps。
- 使用单飞/互斥锁或早期刷新策略防止缓存击穿。
- 为缓存失败设降级方案(返回老数据或降级到更简单页面)。
- 随机化 TTL 防止大规模同时过期。
- 在灰度流量上先跑新策略,观察 24–72 小时再全量推广。






















