Code前端首页关于Code前端联系我们

高并发业务场景下,Redis缓存和MySQL数据一致性解决方案

terry 2年前 (2023-09-26) 阅读数 45 #数据库

在高并发业务场景中,数据库大多数情况下是用户并发访问的最薄弱环节。因此,需要使用Redis进行缓冲操作,让查询先来到Redis,而不是像MySQL那样直接访问数据库。

该业务场景主要解决从Redis缓存读取数据的问题。业务操作一般是按照下图流程进行的。

读取缓存步骤一般没有问题,但一旦涉及到数据更新:数据库和缓存更新,缓存(Redis)和数据库(MySQL)之间就容易出现数据一致性问题。

是否先写入MySQL数据库,然后清除Redis缓存;或者先清除缓存再写入数据库,可能会出现数据不一致的情况。举个例子:

1。当Redis缓存被清空后,还没来得及写入MySQL数据库,另一个线程过来读取,判断缓存为空。然后它从数据库中读取数据并将其写入缓存。此时缓存是针对脏数据的。

2。如果先写库,而在清除缓存之前写库的线程宕机了,而没有清除缓存,也会出现数据不一致的情况。

由于写入和读取是同时进行的,无法保证顺序,所以缓存和数据库之间存在数据不一致的情况。

如来解决了?这里有两种解决方案,先简单后困难,根据业务和技术成本进行选择。

1。第一种解决方案:使用延迟双删除策略

在写数据库前后执行(关键)操作,并设置合理的超时时间。

伪代码如下

public void write(String key,Object data){ Key(key); (data); (500); Key(key); }

2。具体步骤是:

1)先清除缓存

2)然后写入数据库

3)休眠300-500毫秒

4)那么如何清除缓存再次确定这个500毫秒,它应该休眠多长时间?

您需要评估项目中耗时的数据读取业务逻辑。这样做的目的是保证读请求结束后,写请求可以清除读请求造成的缓存脏数据。

当然,这个策略也考虑到了Redis与数据库主从之间的同步耗时。最后写入数据的睡眠时间:在读取数据业务逻辑所花费的时间上加上几百毫秒。例如:休眠1秒。

3。设置缓存过期时间

理论上来说,设置缓存过期时间是保证最终一致性的一个解决方案。所有的写操作都以数据库为准。只要达到了缓存过期时间,后续的读请求自然会从数据库中读取新的值并重新填充缓存。

4。该方案的缺点

结合双删除策略+缓存超时设置,最坏的情况就是超时时间内数据不一致,增加了写查询的时间。

2。第二种方案:异步更新缓存(基于订阅binlog的同步机制)

1。总体技术思路:

MySQL Binlog增量订阅使用+消息队列+Redis上增量数据更新

1)读Redis:热点数据基本都在Redis中2)写MySQL:增删改查MySQL上的所有操作

3)更新Redis数据:MySQ数据操作binlog,更新到Redis

2上。 Redis更新

1)数据操作主要分为两个块:

  • 一个是全量(一次性将所有数据写入Redis)
  • 一个是增量(实时更新)

我在说什么这里涉及到的是increment,指的是来自mysql的更新、插入、最后更改的数据。

2)读取binlog后,解析并使用消息队列打印并更新各站的Redis缓存数据。

这样,一旦MySQL发生新的写入、更新、删除等操作,就可以将binlog相关消息打印到Redis上,Redis会根据binlog中的记录来更新Redis。

其实这个机制和MySQL主从备份机制很相似,因为MySQL主从备份也是通过binlog来实现数据一致性的。

您可以使用Kanal(阿里巴巴开源框架)结合MySQL Binlog进行订阅。 Canal模仿Mysql从库的备份请求,让Redis的数据更新达到同样的效果。

这里的消息推送工具,还可以使用其他第三方:Kafka、rabbitMQ等,来推送和更新Redis。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门