如何保证Redis和MySQL的数据一致性?
2025-06-24 12:13:14
来源:新华网
如何保证Redis和MySQL的数据一致性?
简单来说。
该场景主要发生在阅读和写作并发时,数据不一致才会发生。
主要流程是先操作缓存(Redis),或者先操作数据库,操作也分为修改和删除。
一般修改要执行一系列业务代码,因此一般都是直接的。删除成本。较低。
如果我们。先删除Redis中的数据。,修改数据库数据时会出现,其他线程读取Redis,从数据库查并在Redis中写入,但这是脏数据,因此可以使用。延迟双删。战略,再次删除,之所以需要延迟,是因为当Redis在其他线程中设置旧数据时,不要延迟,新数据将被覆盖。。(所以一般要根据自己的业务逻辑来评估大概的时间。)如果需要在这个阶段确保数据一致性,那就只能。上锁,保证强一致性。,因为Redis和数据库是两个服务,原子性只能通过加锁保证c;这影响了系统吞吐量(使用Redis来增加吞吐量是违反的c;也就是说,AP和CP不能同时满足问题),所以一般都是保证。最终一致性。
如果。先修改数据库。,也会出现数据不一致的情况,在修改数据库处理时,其他线程还将读取旧数据处理完数据库后,将删除缓存,确保数据的最终一致性,(所以推荐这个操作)
但是,以上两者都会有删除Redis的失败,可以选择。异步发送消息。到MQ,MQ的线程监控。执行重试删除。
但这里的MQ代码过于耦合,如果需要解耦,你可以提取它们,使用阿里的一个。canal开源框架。主要用途是基于MySQL数据库。增量日志分析。,Canal提供各种语言,提供增量数据订阅和消费。客户端。,当Canal监视binlog的变化时༌会通知Canal的客户端,这个过程就是执行失败后,异步向MQ发送消息c;Canal客户端监听到MQ消息进行重试。
详细来说。
1、引入。
Redis 缓存层,用于实现应用和数据库之间的读取操作c;主要目的是减少数据库 IO,还可以提升数据 IO 性能。
当应用程序需要读取某个数据时,,先试试 Redis 内部加载如果命中,直接返回。如果没有命中从数据库查询,查询数据后,缓存数据 Redis 里面。
在这样的架构中,会出现问题,是一个数据,数据库和数据库同时保存 Redis 里面,当数据发生变化时,,需要同时更新 Redis 和 Mysql,因为更新有先后顺序,并且它不像 Mysql中的多表事务操作,可以满足 ACID 特性。因此,会出现数据一致性问题。
2、同步策略。
要确保缓存与数据库的双写一致,总共有四种方法,即4种同步策略:
先更新缓存,再次更新数据库; 先更新数据库,更新缓存; 先删除缓存,再次更新数据库; 先更新数据库,再次删除缓存。 从这四种同步策略中,我们需要进行比较a;
哪种方法更适合更新缓存和删除缓存?#xff1f;是先操作数据库还是先操作缓存?f;
一般直接删除因为缓存的更新成本更高 (因为你写入数据库的值,很多情况下,缓存不是直接写的c;在写入缓存之前,需要经过一系列复杂的计算。所以,每次写入数据库后再次计算写入缓存值无疑是浪费性能。显然,更适合删除缓存。)删除缓存操作简单,副作用只增加了一次 chache miss,建议大家使用这个策略。
一般先操作数据库,最终一致性更方便保证c;先往下看。
3、操作理解。
先操作缓存。
如果我们。先删除Redis中的数据。,修改数据库数据时会出现,其他线程读取Redis,从数据库查并在Redis中写入,但这是脏数据,因此可以使用。延迟双删。战略,再次删除,之所以需要延迟,是因为当Redis在其他线程中设置旧数据时,不要延迟,新数据将被覆盖。。(所以一般要根据自己的业务逻辑来评估大概的时间。)如果需要在这个阶段确保数据一致性,那就只能。上锁,保证强一致性。,因为Redis和数据库是两个服务,原子性只能通过加锁保证c;这影响了系统吞吐量(使用Redis来增加吞吐量是违反的c;也就是说,AP和CP不能同时满足问题),所以一般都是保证。最终一致性。
先操作数据库。
如果。先修改数据库。,也会出现数据不一致的情况,在修改数据库处理时,其他线程还将读取旧数据处理完数据库后,将删除缓存,确保数据的最终一致性,(所以推荐这个操作)
4、解决。
重试机制一般采用延迟双删和删除。
延迟双删。
发现缓存中没有相应的数据,查库,查询完毕。准备更新缓存期间,另一个写线程完成了写库和删除缓存。(此时,数据库中的数据是新数据,读取线程将缓存更新为旧数据。),一般来说,,发生这种事件的概率很低,但使用延迟双删可以避免这个问题,进一步提高数据的一致性,但缺点是性能会下降。
根据您的具体业务确定具体的超时间,一般来说,几秒钟就足够了。
队列+重试机制。
在上述情况下,Redis删除失败,可采用重试机制。
例如,重试三次如果三次都失败了,记录日志到数据库并发出警告,以便在高并发场景下人工干预,最好在重试中使用异步法,比如发消息到 mq 中间件,实现异步解耦。
也就是选择。异步发送消息。到MQ,MQ的线程监控。执行重试删除。
解耦Cannal。
但这里的MQ代码过于耦合,如果需要解耦,你可以提取它们,使用阿里的一个。canal开源框架。主要用途是基于MySQL数据库。增量日志分析。,Canal提供各种语言,提供增量数据订阅和消费。客户端。,当Canal听到binlog的变化时,#xff0c;会通知Canal的客户端,这个过程就是执行失败后,异步向MQ发送消息c;Canal客户端监控MQ消息执行重试。
MySQL的binlog可以通过这个框架订阅,而canal模仿mysqlslave数据库的备份请求,Redis的数据更新达到了同样的效果。 RocketMQ可用于MQ消息中间的推送。