分布式的环境下, MySQL和Redis如何保持数据的一致性?

本文探讨了在使用MySQL作为主存储与Redis作为缓存时,如何解决数据一致性问题及并发访问下的数据安全性。介绍了先读缓存后读数据库、先写数据库后写缓存的原则,并强调了设置缓存失效时间对于实现最终一致性的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一文讲透数据库缓存一致性问题

缓存失效策略

消息队列异步处理

分布式事务

定期数据同步

缓存更新策略


问题:

一台MySQL,一台Redis,两台应用服务器,用户的数据存储持久化在MySQL中,缓存在Redis,有请求的时候从Redis中获取缓存的用户数据,有修改则同时修改MySQL和Redis中的数据。现在问题是:

1. 先保存到MySQL和先保存到Redis都面临着一个保存成功而另外一个保存失败的情况,这样,如何保证MySQL与Redis中的数据同步?

2. 两台应用服务器的并发访问,如何保证数据的安全性?

解决方法:

数据库和缓存之间一般不需要强一致性。

一般缓存是这样的:

  • 读的顺序是先读缓存,后读数据库
  • 写的顺序是先写数据库,然后写缓存
  • 每次更新了相关的数据,都要把该缓存清理掉
  • 为了避免极端条件下造成的缓存与数据库之间的数据不一致,缓存需要设置一个失效时间。时间到了,缓存自动被清理,达到缓存和数据库数据的“最终一致性”


 
知乎上面的回答,先应付面试,遇到再深入

作者:Doing
链接:https://www.zhihu.com/question/36413559/answer/310691736
链接:https://github.com/liukelin/canal_mysql_nosql_sync
 

一文讲透数据库缓存一致性问题

主要围绕数据库缓存一致性问题展开,详细阐述了缓存的意义、引入缓存后的一致性挑战、更新缓存的手段、最终一致性的保证方法、减少缓存删除 / 更新失败的措施、复杂多缓存场景的处理方式以及通过订阅 MySQL binlog 处理缓存的方式。

  1. 缓存的意义:缓存通过使用高速存储介质(如 Redis)或就近使用本地内存,以空间换时间的方式提升读性能,帮助业务应对高流量读请求。
  2. 引入缓存后的一致性挑战:数据同时存在于数据库和缓存中,由于两者之间无事务保证,无法做到强一致,但可通过优化使不一致时间窗口尽可能短,达到最终一致 。
  3. 更新缓存的手段:常见策略有更新数据库后更新缓存、更新数据库前更新缓存、更新数据库后删除缓存、更新数据库前删除缓存。分析各策略在并发场景下的潜在问题,综合来看,更新数据库后删除缓存更适合读多写少场景,更新数据库后更新缓存适合读写相当或写多读少场景。
  4. 最终一致性如何保证:给缓存设置过期时间,当出现更新 Redis 失败等极端场景时,缓存失效后重新查询数据库并回写,可保证最终一致性。
  5. 如何减少缓存删除 / 更新的失败:借助消息中间件(如 RocketMQ)的重试机制减少不一致情况。若消息中间件无事务消息特性,可采用消息表方式确保更新数据库和发送消息一起成功。
  6. 如何处理复杂的多缓存场景:一个数据库记录更新可能涉及多个 Key 的更新,可将更新缓存的操作以 MQ 消息方式发送,由不同系统或专门系统订阅并聚合操作 。
  7. 通过订阅 MySQL binlog 的方式处理缓存:利用类似 Canal 的产品订阅 MySQL 的 binlog,监听数据变化,集中处理相关缓存,实现缓存与数据库的一致性。

在分布式环境下,要保证 MySQL 和 Redis 数据的一致性,可采用以下几种方法:

缓存失效策略

  • 读操作:先从 Redis 里读取数据,若未命中,再从 MySQL 中读取,然后把数据存入 Redis。
  • 写操作:先更新 MySQL 中的数据,接着使 Redis 里的缓存失效。下次读取时,会重新从 MySQL 加载最新数据到 Redis。

消息队列异步处理

借助消息队列(如 Kafka、RabbitMQ),异步地更新 Redis 缓存。

  • 写操作:先更新 MySQL 数据,然后把更新消息发送到消息队列。
  • 消息消费:消费者从消息队列接收消息,更新 Redis 中的缓存。这种方式能确保即使在更新 Redis 时出现失败,也可通过重试机制保证最终一致性。

分布式事务

利用分布式事务框架(如 Seata)保证 MySQL 和 Redis 的操作在同一个事务里。

  • 两阶段提交(2PC):在事务开始时,协调者向所有参与者(MySQL 和 Redis)发送准备请求,参与者执行操作并反馈结果。若所有参与者都准备好,协调者发送提交请求;若有参与者失败,协调者发送回滚请求。
  • 补偿事务:当某个操作失败时,执行补偿操作来恢复到之前的状态。

定期数据同步

定期把 MySQL 中的数据同步到 Redis。可使用定时任务或者触发器,周期性地对比 MySQL 和 Redis 中的数据,若有差异就进行更新。

缓存更新策略

  • 更新缓存:在更新 MySQL 数据后,同时更新 Redis 中的缓存。不过这种方式可能会遇到并发问题,需要使用锁机制来保证数据一致性。
  • 延迟双删:更新 MySQL 数据后,先删除 Redis 缓存,然后在一定时间后再次删除 Redis 缓存,以此避免在更新 MySQL 数据时,有其他请求读取到旧数据并写入 Redis。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值