当前位置: 首页 > 科技观察

Redis和MySQL如何保持数据一致性?

时间:2023-03-19 17:05:17 科技观察

在高并发场景下,大量请求直接访问Mysql很容易造成性能问题。因此,我们将使用Redis来缓存数据,减少对数据库的请求。但是Mysql和Redis是两个不同的数据库,如何保证不同数据库之间数据的一致性是非常关键的。1、数据不一致的原因在高并发的业务场景中,数据库往往是用户并发访问中最薄弱的环节。所以需要使用redis做一个缓冲操作,让请求先访问redis,而不是直接访问mysql等数据库。读取缓存这一步一般没有问题,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存(Redis)和数据库(MySQL)之间的数据一致性问题。该业务场景主要解决从Redis缓存中读取数据的问题,一般按照下图的流程进行业务操作。2.先后删除缓存的问题是否先写入MySQL数据库,再删除Redis缓存;或者先删除缓存,再写入库,可能会出现数据不一致的情况。1.先删除缓存。如果先删除Redis缓存数据,还没来得及写入MySQL,另一个线程过来读取,发现此时缓存为空,再去Mysql数据库读取旧数据写入缓存。这时候缓存的是脏数据。然后更新数据库后,发现Redis和Mysql之间存在数据不一致的问题。2、删除缓存后,如果先写库,再删除缓存,不幸的是写库的线程挂了,导致缓存没有删除。这个时候直接读取。取回旧缓存最终会导致数据不一致。因为写入和读取是并发的,顺序无法保证,缓存和数据库之间会出现数据不一致的情况。三、解决方案1、延时双删策略(1)基本思路:写数据库前后分别执行redis.del(key)操作,并设置合理的超时时间。伪代码如下:publicvoidwrite(Stringkey,Objectdata){redis.delKey(key);db.updateData(数据);线程.sleep(500);redis.delKey(key);}br(2)具体步骤:先删除缓存,然后写入数据库休眠500毫秒再删除缓存。问题:这500毫秒是怎么确定的,应该休眠多长时间?您需要评估您项目的读取数据业务逻辑的耗时。这样做的目的是保证读请求结束,写请求可以删除读请求造成的缓存脏数据。当然这个策略也考虑到了redis和数据库主从同步的耗时问题。最后写数据休眠时间:在读数据业务逻辑耗时的基础上,增加几百ms。例如:睡眠1秒。(3)设置缓存过期时间是重点。理论上,为缓存设置一个过期时间是保证最终一致性的一种解决方案。所有写操作都基于数据库。只要达到缓存过期时间,缓存就会被删除。如果请求被读取,则从数据库中读取新值,然后回填缓存。(4)该方案的缺点是结合双删策略+缓存超时设置,所以最坏的情况是:在缓存过期时间内发生数据不一致,增加写请求的时间。2、异步更新缓存(基于Mysqlbinlog的同步机制)(1)总体思路a.涉及更新数据操作,使用Mysqlbinlog增量订阅消费b.向消息队列发送消息c.通过消息队列消费增量数据更新到Redisd。操作条件:读取Redis缓存:热数据写入Redis上的Mysql:增删改查都在Mysql中进行更新Redis数据:Mysql数据操作全部记录在binlog中,通过消息队列及时更新到Redis(2)Redis更新过程a.数据操作主要分为两种:一种是全量(一次性将所有数据写入Redis),另一种是增量(实时更新)。这里说的增量,指的是mysql更新、插入、删除变更数据。b.读取binlog后进行分析,利用消息队列推送更新各站的redis缓存数据。这样,一旦MySQL中产生新的写入、更新、删除等操作,就可以将binlog相关的消息推送到Redis,然后根据binlog中的记录更新Redis。其实这种机制很像MySQL的主从备份。机制,因为MySQL的主备也是通过binlog实现数据一致性的。在这里,你还可以使用其他第三方:kafka、rabbitMQ等来推送更新Redis!在高并发的应用场景中,如果对数据一致性要求很高的情况下,需要定位数据和缓存不一致的原因。高并发场景下数据一致性的解决方案有两种,延迟双删策略和异步更新缓存方案。另外,设置缓存的过期时间是保证数据一致性的关键操作,需要结合业务合理设置。