← 每日面试题 学习看板

什么情况下会出现数据库和缓存不一致的问题?

面试题/03数据库中间件/02Redis/06缓存典型问题与一致性/什么情况下会出现数据库和缓存不一致的问题?.md

https://chat.deepseek.com/share/ce5pvlaaj32ar3gyxt


面试记录 2026-09-20

题目:什么情况下会出现数据库和缓存不一致的问题?

难度:medium

标签:db/redis/cache, general/knowledge

评分:⭐⭐⭐⭐☆(4/5)

我的回答

数据库缓存不一致,核心原因就是非原子性数据库跟缓存的更新。然后非原子性造成问题,衍生的也就是并发问题,在并发情况下,在并发状态下,数据的更新由于不同线程的不同操作,导致相互的不一致。另外就是单个线程内,数据库或者缓存的更新失败,另一者更新成功导致的数据库与缓存不一致,其实也是原子性的问题导致的。一般处理这种问题主要是原子性的操作或者是补偿性的操作,然后最终的话可能是选择强一致或者最终一致性来处理这个问题;正常是先更新数据库,数据库更新完后删除缓存,然后异步的或者是延迟的再去删除一次缓存,确保数据库数据读取到缓存中是一个新值的数据。当然这块可能通过一些异步的方案去数据库读数据库更新日志,读 binlog 日志,然后去通过买四,通过其他的工具去异步的执行缓存删除。然后缓存更新的话,基本上都是通过二次调用去读取的。这里边会有一些衍生问题,比如主从数据库。二者会有一定的时间延迟,主库更新后,从库没有读取到,但是缓存已经更新了,而读一般是从从库来的,这时候就导致主库的数据和缓存数据不一致,也会产生数据库缓存不一致问题。常规的最处理最常见的处理方式就是更新完数据库删缓存,然后另外给缓存设一个相对合理的过期时间,哪怕数据出现了问题不一致,也可以正常的在一定时间周期后恢复正常的数据。

点评

优点:

不足:

补充:

  1. 6 大不一致场景结构化列举
  2. 推荐模式 Cache-Aside(读时回填 + 写时删缓存)
  3. 删除优于更新:并发写时更新缓存会 race,删除让下次读自然回填
  4. 延迟双删延迟 500ms-1s(覆盖主从同步周期)
  5. 强一致方案:Binlog 订阅(Canal)+ MQ 重试 / 事务性消息 / CDC / Seata
  6. 兜底:TTL 是最终一致性的安全网

完整讲解

第一部分:知识重点剖析

核心考点定位:考察对不一致根因的枚举能力 + 解决方案的层次选型能力,而非只答一个"延迟双删"。

知识点拆解:

  1. 不一致的 6 大场景:
  1. 三大经典模式对比:
  1. 为什么"删除缓存"优于"更新缓存":更新缓存在并发写时会有旧值覆盖新值的 race,删除让下次读自然回填最新值
  1. 延迟双删正确姿势:更新 DB → 删缓存 → 延迟 500ms-1s(覆盖主从同步周期)→ 再删一次;实现用线程池延迟任务或 MQ 延迟消息
  1. 强一致性方案(按侵入性从小到大):
  1. 兜底策略:TTL 是最终一致性的安全网;监控不一致率(定时抽样对比)
  1. 工程实践清单:

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. Canal 如何保证不丢消息?
  1. 延迟双删的 N 值怎么定?
  1. 读写分离下如何避免读到旧值?
  1. Seata AT 模式原理?为什么侵入小?
  1. 如何监控缓存不一致率?
  1. 库存扣减场景如何保证一致性?

第三部分:面试者参考回答(300-600 字口语化)

面试官您好,DB 与缓存不一致的根因是非原子性 + 并发,具体有 6 类场景:

场景 1:更新 DB 后删缓存失败,脏数据驻留到 TTL。场景 2:删缓存后更新 DB 失败,下次读回填旧值。场景 3:并发 race——读线程读到旧值,写线程更新 DB 删缓存,读线程把旧值写回缓存,脏数据长期驻留。场景 4:先删缓存再更新 DB,删除后并发读回填旧值。场景 5:先更新缓存再更新 DB,DB 失败则缓存是新值 DB 是旧值。场景 6:主从延迟,主库写完从库未同步,读走从库拿旧值。

模式选型:我们通用场景用 Cache-Aside(读时回填、写时删缓存),删除比更新安全——并发写时更新缓存会有旧值覆盖新值的 race,删除让下次读自然回填最新值。

延迟双删:更新 DB → 删缓存 → 延迟 500ms-1s(覆盖一次主从同步周期)→ 再删一次,清掉并发读回填的脏值。实现用线程池延迟任务或 MQ 延迟消息。

强一致场景(订单、余额):用 Binlog 订阅(Canal)消费 binlog → MQ → 删缓存,业务无侵入;或者用 RocketMQ 事务性消息,DB 事务与消息发送原子;Seata AT/TCC 侵入大不推荐。

兜底:TTL 是最终一致性的安全网,业务可容忍的脏数据时间窗(订单 5min、商品详情 1h)。配合不一致率监控:定时抽样对比 DB 与缓存,超阈值告警。

实际项目我做过一个坑:一开始只用了"更新 DB + 删缓存",压测发现偶发脏数据。查下来是主从延迟导致读从库拿旧值。加了延迟双删(延迟 1s)后问题解决。后来核心订单场景改成了 Canal + MQ 强一致方案。