1、缓存一致性问题的本质:为什么会出现缓存不一致?CAP理论在缓存场景下的体现。
缓存不一致,本质上是分布式系统中多个数据副本之间状态偏离的问题。当数据同时存储在缓存(如 Redis)和持久化数据库(如 MySQL)中时,由于更新顺序、网络延迟、并发写入等因素,不同副本在同一时刻可能对外呈现不同的值。理解这一问题的根源,需要从分布式系统的核心理论——CAP 理论切入。
1.1 缓存不一致的典型场景
以下三种操作模式是导致缓存不一致的常见原因:
| 场景 | 操作顺序 | 不一致结果 |
|---|---|---|
| 先更新数据库,后删除缓存 | 写 DB → 删 Cache → 读请求回填旧数据 | 缓存中残留旧值,新请求读到脏数据 |
| 先删除缓存,后更新数据库 | 删 Cache → 写 DB → 并发读请求回填旧数据 | 缓存回填了更新前的旧值,覆盖了后续的正确值 |
| 双写并发(写 DB + 写 Cache) | 写 Cache A → 写 DB A → 写 Cache B → 写 DB B | 缓存中最终值为 A,数据库中最终值为 B,永久不一致 |
关键洞察: 缓存不一致的核心矛盾在于“写操作无法原子性地同时完成两个存储系统”,且“读操作可能在写操作中间时刻插入”。
1.2 CAP 理论在缓存场景下的体现
CAP 理论指出,分布式系统在 C(一致性)、A(可用性)、P(分区容错性) 三者中最多只能同时满足两个。在缓存 + 数据库的架构中,网络分区(P)是必然存在的(缓存与数据库可能部署在不同节点),因此我们必须在 C 和 A 之间做出权衡。
缓存场景的 CAP 取舍: 大多数互联网业务选择 AP(可用性 + 分区容错性),即优先保证缓存可读,容忍短时间的不一致,再通过最终一致性机制修复。金融、库存等强一致场景则选择 CP(一致性 + 分区容错性),通过分布式锁或同步写穿缓存来保证强一致。
1.3 缓存不一致的根本原因分类
从 CAP 视角出发,可以将缓存不一致的根因归纳为以下四类:
- 并发写冲突(C 缺失): 多个写请求同时操作缓存和数据库,缺乏全局锁或版本控制,导致写顺序不一致。
- 网络延迟与分区(P 固有): 缓存与数据库之间的网络抖动,导致更新指令丢失或乱序到达。
- 回填时序错乱(A 优先): 为了保持高可用,允许读请求在缓存未命中时回填数据,但回填操作可能发生在旧数据写入之后、新数据写入之前。
- 缓存过期策略滞后: TTL 设置过长,导致缓存中长时间保留过期数据,数据库已更新但缓存未刷新。
常见误区: 很多开发者认为“只要先删缓存再更新数据库就能保证一致”,实际上在并发读回填场景下,这反而会导致更长时间的脏数据。正确的做法是结合延迟双删、版本号校验或 binlog 监听等补偿机制。
1.4 一致性模型对比
不同的业务场景需要选择不同的一致性模型,以下是缓存场景中常见的三种模型:
| 一致性模型 | 定义 | 缓存实现方式 | 典型场景 |
|---|---|---|---|
| 强一致性 | 任何读操作都能读到最新写入的值 | 同步写穿(Write-Through)+ 分布式锁 | 库存扣减、账户余额 |
| 最终一致性 | 经过一段时间后,所有副本最终达到一致 | 异步删除 + 消息队列补偿 | 用户资料、文章详情 |
| 弱一致性 | 不保证后续读能读到最新值 | 仅依赖 TTL 过期 | 非关键统计数据、排行榜 |
1.5 从 CAP 到缓存一致性闭环
理解 CAP 理论在缓存场景下的体现,是构建缓存一致性闭环的第一步。后续章节将围绕以下闭环链路展开:
- 识别不一致: 通过监控和日志发现缓存与数据库的差异。
- 定位根因: 分析是并发、网络还是策略导致的不一致。
- 选择策略: 根据业务对 C/A 的需求,选择强一致或最终一致方案。
- 实施补偿: 通过延迟双删、版本号、binlog 监听等手段修复不一致。
- 验证闭环: 通过自动化测试和流量回放验证一致性是否恢复。