分布式环境下,强一致性往往意味着高昂的性能代价。实践中我们通常追求最终一致性,即允许短暂的数据差异,但通过机制确保数据最终同步。本文将从原理、策略到进阶方案,梳理 MySQL 与 Redis 双写一致性的常见解法。
一、为什么会出现不一致?
在包含 MySQL(可靠数据源)和 Redis(缓存)的系统中,写操作需同时处理两端。任何一步失败或延迟都会导致不一致:

常见场景包括:
- 写 MySQL 成功,写 Redis 失败:缓存保留旧数据。
- 写 Redis 成功,写 MySQL 失败:缓存存在脏数据。
- 并发读写:更新数据库时,另一线程读取了旧缓存并回填。
二、核心策略与模式
根据业务对一致性和性能的要求,可选择不同模式。
1. Cache-Aside Pattern(旁路缓存模式)
这是最经典的做法。应用直接交互数据库和缓存,缓存不作为写入必经之路。
- 读流程:查 Redis → 命中返回;未命中查 DB → 回写 Redis → 返回。
- 写流程:更新 DB → 删除 Redis 缓存。
为什么删缓存而不是更新?
- 性能:避免频繁写入不常读的数据。
- 并发安全:删除是幂等的,更新顺序难控,易产生脏数据。
尽管'先更库后删缓存'能解决大部分问题,但在极端并发下仍有窗口期风险:线程 A 更库,线程 B 读不到缓存去查库(读到旧值),再写回缓存,此时 A 才删缓存。不过由于 DB 写耗时通常大于读,这种情况概率较低。
2. Write-Through / Read-Through(穿透读写模式)
应用只写缓存,缓存组件负责同步写库。读未命中时由缓存组件自动加载。
- 优点:逻辑透明,一致性较好。
- 缺点:每次写都涉及 DB,性能损耗大,依赖中间件支持。
3. Write-Behind(异步写回模式)
应用写缓存后立即返回,后台批量异步刷库。
- 优点:写性能极高。
- 缺点:缓存宕机可能丢数据,一致性最弱。适合计数、点赞等可容忍丢失的场景。
三、进阶方案:弥补 Cache-Aside 缺陷
为了进一步降低不一致窗口,可引入额外机制。
1. 延迟双删
针对并发回写旧数据的问题,增加一次延迟删除。
- 更新 DB。
- 删除缓存。
- 休眠 500ms~1s(估算读耗时)。
- 再次删除缓存。
第二次删除是为了清理掉第一次删除后、其他线程可能写入的旧缓存。虽然有效,但增加了写入耗时,且休眠时间难以精确设定。
2. 消息队列异步删除
将删除操作发往 MQ(如 RocketMQ, Kafka),消费者重试直到成功。
- 优点:解耦,保证至少执行一次。
- 缺点:架构复杂度上升。
3. 数据库 Binlog 同步(推荐)
利用 Canal、Debezium 等中间件订阅 MySQL Binlog,解析变更后再操作 Redis。



