先说结论

常见方案是 Cache Aside:读请求先查缓存,未命中再查数据库并回填;写请求先更新数据库,再删除缓存。它通常保证最终一致性,而不是严格强一致。

为什么是删除而不是更新缓存?

更新缓存可能依赖多张表计算,也可能被低频读取造成无效写入。删除缓存让下一次读取根据最新数据库状态重新构建,逻辑更简单。

并发窗口

即使先更新数据库再删除缓存,也可能出现旧读请求在删除之后把旧值重新写回缓存。实际系统会根据一致性等级选择过期时间、延迟二次删除、互斥重建或基于消息的失效通知。

消息与 Binlog 方案

写入数据库后发送消息删除缓存,需要处理消息发送失败和重复消费。更可靠的做法是使用事务消息、Outbox,或者订阅数据库 Binlog,把数据变更转成缓存失效事件。

如何选择方案?

  • 商品详情等读多写少场景:Cache Aside + 合理 TTL。
  • 库存、余额等强约束数据:数据库或专门一致性服务作为判断依据,不能只信缓存。
  • 大规模派生缓存:CDC/Binlog + 消息队列异步失效。
  • 热点 key:增加互斥重建、逻辑过期和限流,防止击穿。

怎么讲更清楚

先说明业务需要的是强一致还是最终一致,再给出读写流程、失败补偿、监控指标和降级方案。脱离业务直接说“延迟双删就能保证一致”是不严谨的。

并发时序为什么重要

先删缓存再写数据库时,另一个线程可能在写库前读到旧值并回填。先写数据库再删缓存仍有极小窗口,但发生条件更苛刻,也更容易通过 TTL 和可靠删除补偿。延迟双删可以降低部分并发回填风险,但等待时间难以精确设置,不能代替可靠重试。

常见问题

追问 1:为什么删除缓存而不是更新缓存?

删除是幂等操作,容易重试;直接更新还要处理并发写入顺序,并可能为不再读取的数据做无效维护。

追问 2:如何做到真正强一致?

旁路缓存天然适合最终一致。关键读可绕过缓存,或使用支持事务的一致性存储,但必须接受更高延迟或更低可用性。

追问 3:分布式锁能解决全部一致性问题吗?

不能。它能限制并发回源,却无法原子覆盖数据库提交与缓存删除,还要处理锁超时、进程暂停和故障切换。