MySQL与Redis缓存一致性:四种更新策略对比
在典型的互联网架构中,MySQL 承担着数据持久化的重任,保证数据的可靠性;而 Redis 作为高速缓存,大幅提升数据访问性能。但二者并用时,如何保证MySQL与Redis缓存一致性(即缓存一致性问题)成为经典难题。
本文深入剖析缓存不一致产生的根本原因,并详细对比四种主流的缓存更新设计模式,帮助你根据业务场景做出合理取舍。
一、缓存不一致是如何产生的?
如果数据从不变更,缓存与数据库自然永远一致。但实际业务中,数据更新频繁,每次更新都要同时操作数据库和缓存——两个独立的系统,无法保证原子性。在并发读写场景下,就会出现短暂的数据不一致。理论上分布式事务可以做到强一致,但实现成本过高,很少在生产中采用。
因此,业界公认的思路是:不追求强一致,而是保证最终一致,并通过合理的设计将不一致的影响时间和范围降到最低。
二、四种缓存更新设计模式详解
以下是经典的四种缓存更新策略,各自适用不同场景。我们将逐一剖析其流程、优缺点及并发下的表现。
1. 先删除缓存,再更新数据库(不可取)
流程:删除缓存 → 更新数据库。这种方案在并发读写下极易产生长时间的脏数据。
图:先删除缓存再更新数据库(并发场景导致脏数据)
并发问题示例: 线程A删除缓存后尚未更新数据库,线程B读取缓存未命中,从数据库读到旧数据并写入缓存,然后线程A才更新数据库。最终缓存中是旧数据,数据库是新数据,产生不一致。
结论: 一般不建议使用这种方式。
2. 先更新数据库,再删除缓存(Cache Aside Pattern)
流程:更新数据库 → 删除缓存。这是最常用的模式,被诸多大厂实践验证。
图:先更新数据库再删除缓存
并发表现: 极小概率出现短暂不一致(例如线程A更新数据库后、删除缓存前,线程B读到旧缓存),但很快缓存被删除,后续请求会读数据库并重建缓存,最终一致。大部分业务可接受此短暂窗口。
✅ 优点: 实现简单,脏数据风险低。
✅ 适用场景: 读多写少的通用业务。
3. 只更新缓存,由缓存同步更新数据库(Read/Write Through Pattern)
业务代码只操作缓存,缓存层负责同步写入数据库。读操作若缓存未命中,缓存也同步从数据库加载。
图:Write Through 模式
优点: 缓存不一致概率极低,对业务层透明。
缺点: 需要对缓存中间件进行深度改造(如自定义Redis代理),实现成本高。
🔧 适用场景: 对一致性要求极高,且有自研缓存中间件能力的团队。
4. 只更新缓存,由缓存异步更新数据库(Write Behind Cache Pattern)
业务只更新缓存,立即返回;缓存以异步方式(如消息队列、后台线程)批量或延时写入数据库。
图:Write Behind 异步写模式
优点: 读写性能极高,操作内存即返回,适合超高吞吐场景。
缺点: 非强一致,缓存宕机会导致数据丢失;实现复杂,需要处理异步重试和幂等。
⚠️ 适用场景: 对性能要求极致,可容忍少量数据丢失(如点赞数、浏览计数)。
三、方案对比与选型建议
| 模式 | 一致性保障 | 性能影响 | 实现复杂度 | 推荐指数 |
|---|---|---|---|---|
| 先删缓存后更新DB | 低(极易脏数据) | 中 | 简单 | ★☆☆☆☆ |
| Cache Aside | 中(最终一致) | 高(删除缓存轻量) | 简单 | ★★★★★ |
| Read/Write Through | 高(同步写入) | 中(同步写入DB有开销) | 高 | ★★★☆☆ |
| Write Behind | 低(可能丢数据) | 极高(纯内存操作) | 高 | ★★☆☆☆ |
综合建议: 绝大多数业务场景下,Cache Aside Pattern(先更新数据库,再删除缓存) 是最佳选择。它兼顾了简单性和一致性,也是 京东云Redis 和 云数据库RDS 官方推荐的使用模式。
四、总结
没有完美的缓存一致性方案,只有最适合当前业务的方案。在设计系统时,请牢记:
- 如果不能容忍任何不一致,请直接读数据库,不要使用缓存。
- 如果可以容忍秒级延迟,Cache Aside 完全够用。
- 如果写吞吐量极大且允许少量丢失,可考虑 Write Behind。
- 任何缓存更新逻辑,都要配合缓存过期时间作为兜底,避免永远脏数据。
希望本文能帮助你更好地处理 MySQL 与 Redis 的缓存一致性问题。