高并发业务场景下,Redis缓存和MySQL数据一致性解决方案
在高并发业务场景中,数据库大多数情况下是用户并发访问的最薄弱环节。因此,需要使用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前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。