Skip to content

缓存问题与一致性

缓存雪崩、击穿与穿透

问题表现常见原因应对思路
缓存雪崩大量 key 同时失效,流量集中打到下游批量设置同一 TTL、缓存集群故障TTL 加随机值、多级缓存、限流熔断、预热、高可用与降级
缓存击穿(热点 key)某个高并发热点 key 过期,瞬间大量请求回源热点过期/被淘汰互斥重建、逻辑过期+异步刷新、热点永不过期(配合更新)
缓存穿透请求的 key 在缓存和数据库都不存在,持续回源恶意构造无效 key、参数错误参数校验、缓存空值(短 TTL)、布隆过滤器、限流/风控

缓存击穿不是普通“缓存没有但数据库有”的单次未命中;其重点是高并发同时回源。布隆过滤器可能有假阳性但不应有假阴性(前提是正确构建),适合拦截大部分确定不存在的 key。

Cache Aside(旁路缓存)

这是最常用模式:

读路径

  1. 读取缓存,命中直接返回;
  2. 未命中则读取数据库;
  3. 将结果(或短 TTL 空值)写入缓存并返回。

写路径

  1. 先更新数据库
  2. 再删除/失效缓存,而不是直接更新缓存。

先写数据库再删缓存可降低写入失败导致缓存提前失效的问题。删除操作应具备重试/补偿能力,可使用消息队列、binlog 订阅或定时校验处理异常。

并发不一致窗口

即使使用 Cache Aside,仍可能短暂读旧数据:写事务提交后、缓存删除前,读请求可命中旧缓存。另一个典型竞态是:

text
读请求:缓存未命中 → 读取旧数据库值 ───────────────┐
写请求:                更新数据库 → 删除缓存         │
读请求:                                            回填旧值

常用缓解:

  • 缓存设置 TTL,限制脏数据存活;
  • 对关键 key 的回填做版本校验、互斥/单飞(singleflight)控制;
  • 使用“延迟双删”作为概率性补偿:更新 DB → 删除缓存 → 延迟后再删一次。它不是严格一致性保证;
  • 对强一致业务直接读主库/事务内数据,或采用事件驱动的版本化缓存与可靠消息。

其他缓存写策略

策略含义取舍
Read Through缓存组件负责未命中时加载底层数据对调用方透明,但需缓存层支持
Write Through写缓存时同步写入底层存储一致性较好,写延迟较高
Write Behind / Write Back先写缓存,异步批量落库写性能高,但有丢数据和最终一致性风险

不要脱离业务选择策略:商品展示可接受短暂最终一致;余额、库存扣减、权限变更等关键路径需要更严格的事务、条件更新、幂等和审计设计。

使用 Markdown 与 VitePress 构建