1019 字
约 3 分钟
8
S12-J02 · 缓存与数据库一致性

适用读者:被"先删缓存还是先更库"绕晕的人。
前置:S12-J01、S11-A03。
覆盖旧文:870(102) 427(575) 2670(163) 2669(84) = 924 点。
覆盖扩展:E-S12-006(六种方案对比)。
上一篇:S12-J01 · 缓存穿透、击穿、雪崩
下一篇:S12-J03 · 分布式锁。


1. 一句话结论

缓存与 DB 不可能"强一致"(除非牺牲性能),只能做"最终一致"。六种方案的差别在"不一致窗口多长、实现多重"。

方案 窗口 复杂度 适用
先更库、再删缓存 毫秒级 低 默认推荐
先删缓存、再更库 较大 低 ❌ 不推荐
延迟双删 更小 中 高并发写
订阅 binlog 删缓存 最小(秒级) 中 追求稳定一致
定时对账 分钟+ 低 兜底
强一致(分布式锁/2PC) 0 极高 极少数场景

2. 为什么"先更库、再删缓存"是默认解

① 更新 DB
② 删除缓存

竞态分析:

时序 结果
读线程缓存 miss → 读 DB(旧值)→ 写缓存 若②在写缓存之后,缓存被删 → 下次读到新值 ✅
若②在写缓存之前 缓存留下旧值 ❌(窗口极小)

"为什么不是更新缓存而是删除":更新缓存在并发下更容易产生"旧值覆盖新值"(两个写线程顺序错乱);删除是幂等的。


3. 六种方案对比(E-S12-006)

# 方案 关键点
1 先更库后删缓存(Cache Aside) 业界默认
2 先删缓存后更库 窗口大,不推荐
3 延迟双删 更库前删、更库后延迟再删
4 binlog 订阅 由数据变更驱动失效(最稳)
5 定时对账 兜底修复
6 强一致(锁/2PC) 性能代价极大

判据:"业务能容忍多久的旧值?" < 100ms → 方案 4;秒级 → 方案 1/3;无所谓 → 方案 1 + 对账。


4. 三个真实难点

难点 说明
删除失败 缓存删失败 → 旧值长期存在(要重试/补偿)
主从延迟 更库后立即读从库可能读到旧值(S11-A02)
多级缓存 本地缓存无法被"删除"通知到(要广播)

"删除失败怎么补":重试队列 + 对账——这是工程上必须有的兜底。


5. 与 MongoDB/Cassandra 双写的共性(A-2669)

任何"两个存储双写"都有同一个问题:没有跨存储事务。所以:

① 优先选"单一事实来源 + 派生物由变更驱动"(binlog/CDC)
② 双写必须有对账

6. 五个误区

误区 真相
"更新缓存比删除缓存好" 并发下更易脏
"延迟双删能根治" 只是缩小窗口
"删缓存失败无所谓" 旧值会长期存在
"多级缓存能靠删 Redis 失效" 本地缓存要单独通知
"强一致最好" 性能代价常不可接受

7. 自检

  1. 六种方案的窗口与复杂度?
  2. 为什么默认是"先更库后删缓存"?
  3. "延迟双删"具体删两次的时机?
  4. 三个真实难点是什么?
  5. 双写为什么必须有对账?

8. 下一篇

S12-J03 · 分布式锁:SETNX → Redisson → RedLock

一致性讲完,下一篇讲"多实例互斥":锁怎么抢、怎么防误删(实测误删事故)、红锁为什么有争议。


本篇属于系列《S12 · Redis 与缓存》。旧文来源:A-870/427/2670/2669;扩展点 E-S12-006。

S12-J02 · 缓存与数据库一致性
https://www.clxhxhhr.top/posts/5351/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。