【大厂思维】缓存一致性问题解决方案

一、三种方案

  1. 延迟双删:缓存与数据库一致性问题的公认解决方案,也是面试高频考点,在各类技术八股文中均有重点提及。
  2. 租约机制:多见于分布式场景的大厂方案,更适配高并发、大规模架构。对于流量较小的内部 ERP 等系统,通常无需缓存设计,因此极少采用。
  3. 版本号对比机制:同样是大厂常用方案,核心通过数据自带的版本号标识,直观判断数据新旧,进而保障数据一致性。

二、延迟双删

2.1 什么是延迟双删

通过两次缓存删除操作,最大限度降低缓存与数据库的数据不一致风险

  1. 首次删除:更新数据库前,先删除缓存数据。

    作用:避免更新时,请求命中缓存,读取到旧数据

  2. 数据库更新:更新数据库中的数据。

  3. 延迟后第二次删除:等待几秒(具体时间,根据业务需要调整)后,将缓存中的数据再次删除。

    作用:解决首次删除后,数据库更新完成前的并发问题。即有并发请求,旧数据被重新写入缓存的问题

2.2 优缺点

优点:

  1. 实现成本低。
  2. 兼容性强,支持常见的缓存、数据库。
  3. 覆盖并发窗口,降低缓存与数据库的不一致性概率。

缺点:

  1. 可能存在缓存击穿的问题。
  2. 延迟删除时间难以把控。
  3. 依赖异步任务的可靠性。(一般情况下,延迟删除通过定时任务、消息队列实现,如发生故障,难以保证第二次删除)
  4. 无法满足强一致性的要求。

2.3 适用

  1. 中小型规模
  2. 并发量较小,数据库能承受短时的缓存击穿。
  3. 无复杂的分布式架构

三、租约机制

3.1 什么是租约机制

简单的说,就是多个请求查询缓存,只有第一个请求可以获取到令牌后写入缓存。

  1. 缓存中不存在查询的数据时,多个并发请求中,只给第一个颁发“令牌”。
  2. 拿到令牌后,才允许其查询数据库,写入缓存。其他请求,要么等待,要么放弃。

3.2 有缺点

优点:

  1. 防止并发出现混乱,不会出现旧数据覆盖新数据的问题。
  2. 轻量化,依靠Redis Lua脚本实现。
  3. 令牌过期时间可灵活设置。

缺点:

  1. 实现比延迟双删复杂,需要用Lua脚本实现令牌的生成、验证、删除,令牌过期、请求排队也需要考虑。
  2. 存在等待期,未获取到令牌的请求,要么等现有令牌过期,要么放弃,极端情况下部分用户可能需要等待。
  3. 缓存服务依赖度高,令牌的实现在缓存中,缓存一旦宕机,就可能出现租约机制失效的问题。

3.3 适用

  1. 大流量分布式系统
  2. 并发写多的业务
  3. 可接受等待的业务

四、版本号对比机制

4.1 什么是版本号对比机制

给每条数据,添加一个时间戳字段或版本号字段。

写缓存是,先判断版本号的新旧,新版本存入,旧版本丢弃。

4.2 优缺点

优点:

  1. 性能好,直接对比版本号,无需排队等待。
  2. 数据一致性,根据版本号,可防止旧数据覆盖新数据的问题。
  3. 实现较简单,无需考虑令牌的生成、过期等逻辑。
  4. 无锁设计,不会出现锁竞争、死锁等问题。

缺点:

  1. 版本号生成逻辑出现问题,会导致数据更新异常。
  2. 无法解决缓存击穿问题。
  3. 版本号存储占用空间。

4.3 适用

  1. 超大规模的高并发系统。
  2. 读多写少、数据更新频繁的业务。
  3. 需要“强一致性”优先级高于“防止缓存击穿”

五、总结

方案 适用 核心逻辑 优点
延迟双删 中小系统 删除缓存、延迟删除 简单
租约机制 大型系统 令牌的控制逻辑 防缓存击穿
版本号对比机制 超大型系统 版本号对比 无锁,性能好