Redis 缓存与数据库双写不一致¶
一、问题¶
写 DB 和写 Redis 不是原子操作,并发下会不一致。
时序问题导致 Redis 里是旧值。
二、常见方案¶
1. 先更新 DB,再删缓存(Cache Aside)¶
为什么删而不是更新? - 更新缓存可能并发写覆盖。 - 懒加载:下次读时再回源。
2. 延迟双删¶
第二次删是为了清掉"在读过程中被其他线程写回的旧值"。
缺点:sleep 时间不好定,阻塞线程。
3. 订阅 Binlog¶
Canal 监听 MySQL Binlog,异步删缓存。
优点:业务代码无侵入。 缺点:增加 MQ 链路,延迟。
4. 分布式锁¶
把"更新 DB + 删缓存"串行化。
三、为什么不用先更新缓存¶
- 缓存更新并发写容易覆盖。
- 不是所有读都走缓存,更新缓存浪费。
四、一致性要求¶
- 强一致:用分布式锁 + 串行化。
- 最终一致:Canal + MQ,可接受秒级延迟。
- 不要求:直接更新 DB,缓存 TTL 到期自动更新。
五、对比¶
| 方案 | 一致性 | 性能 | 复杂度 |
|---|---|---|---|
| 先更新 DB 再删缓存 | 最终一致 | 高 | 低 |
| 延迟双删 | 最终一致 | 中 | 中 |
| Canal Binlog | 最终一致 | 高 | 高 |
| 分布式锁 | 强一致 | 低 | 高 |
生产推荐
先更新 DB 再删缓存 + Canal 兜底。延迟双删是过渡方案。