Redis/MySQL 数据一致性
Redis缓存与MySQL数据库的数据一致性解决方案,包括双写、删除缓存、延迟双删等策略
背景
在现代Web应用中,Redis作为缓存层与MySQL作为持久化存储层的组合非常常见。这种架构虽然能显著提升性能,但也带来了数据一致性的挑战。当数据在Redis和MySQL之间需要保持同步时,如何确保两个数据源的一致性成为关键问题。
数据不一致通常发生在以下场景:写操作成功更新了MySQL但Redis缓存更新失败、并发读写操作导致的竞态条件、缓存失效策略不当等。
核心内容
数据不一致的根本原因
核心挑战
数据不一致主要源于四个关键因素:
- 写操作时序问题:==先写缓存还是先写数据库==的决策
- 并发读写竞态:多个线程同时操作相同数据产生的==竞态条件==
- 网络分区:缓存与数据库之间的==网络故障==
- 缓存失效策略:==过期时间设置不当==导致的同步问题
一致性解决方案
原理:在写操作时,同时更新缓存和数据库
流程:
- 开启事务
- 更新MySQL数据库
- 更新Redis缓存
- 提交事务
优点:数据一致性高
缺点:性能开销大,两个写操作都需要成功
适用场景:金融交易、账户余额等强一致性要求场景
原理:写操作时删除缓存,读操作时重新加载
流程:
写操作:
- 删除Redis缓存
- 更新MySQL数据库
读操作:
- 先查Redis缓存
- 缓存未命中则查MySQL
- 将结果写入Redis
优点:实现简单,性能较好
缺点:存在短暂的缓存不一致窗口
适用场景:大多数Web应用场景
原理:在删除缓存后,延迟一段时间再次删除,解决并发竞态
流程:
- 删除Redis缓存
- 更新MySQL数据库
- 延迟一段时间(如500ms)
- 再次删除Redis缓存
优点:有效解决并发竞态问题 缺点:实现复杂,延迟时间需要合理设置
适用场景:高并发写入场景
原理:通过消息队列异步同步数据
流程:
- 更新MySQL数据库
- 发送消息到消息队列
- 消费者从队列读取消息并更新Redis
优点:解耦,提高系统可用性 缺点:最终一致性,存在延迟
适用场景:大数据量、异步处理场景
一致性级别选择
一致性级别对比
| 一致性级别 | 描述 | 适用场景 | 性能影响 |
|---|---|---|---|
| 强一致性 | 实时同步,数据完全一致 | 金融交易、账户余额 | ⭐⭐⭐⭐⭐ |
| 最终一致性 | 短暂延迟后达到一致 | 商品库存、用户信息 | ⭐⭐⭐ |
| 弱一致性 | 不保证实时一致 | 浏览量、点赞数 | ⭐ |
选择建议: - 强一致性:对数据准确性要求极高的场景 - 最终一致性:大多数业务场景的平衡选择 - 弱一致性:对实时性要求不高的统计类数据
示例
Go语言实现删除缓存策略
代码实现
注意事项
⚠️ 常见问题
缓存穿透
问题:查询不存在的数据导致频繁访问数据库
解决方案:缓存空值或使用布隆过滤器
缓存雪崩
问题:大量缓存同时失效导致数据库压力骤增
解决方案:设置不同的过期时间,使用热点数据永不过期
缓存击穿
问题:热点数据失效瞬间大量请求打到数据库
解决方案:使用互斥锁或永不过期策略
✅ 最佳实践
缓存策略优化
合理设置缓存过期时间:根据业务特点设置TTL
- 高频读数据:设置较长的TTL
- 低频读数据:设置较短的TTL
- 实时性要求高:设置短TTL或实时同步
使用读写锁:防止并发写操作导致的数据混乱
- 读多写少:使用读写锁提高并发性能
- 写操作频繁:考虑分布式锁
监控缓存命中率:及时发现缓存策略问题
- 命中率低于80%:需要优化缓存策略
- 命中率波动大:检查缓存失效策略
设计降级方案:缓存故障时能正常服务
- 直接访问数据库:保证基本功能可用
- 限流保护:防止数据库被压垮
延伸阅读
维护人:yiiewang · 最后更新:2026-07-04