在实际开发过程中,我们经常会遇见在高并发的的情况下,大量的请求访问Mysql数据库,会造成性能安全问题。所以,我们很多时候会把数据写入到Redis里面,用作缓存来减少数据库的压力,但是Redis 和 MySQL是两种不同类型的数据库,我们要怎样去保证它们之间的数据是一致性的呢?
数据不一致的原因当数据并发量非常大的情况下,用户的并发访问会对数据库的安全造成极大的安全隐患。
因此,我们就需要使用到Redis来做一个缓存的操作,可以让用户请求先访问Redis,而不直接访问到数据库。
然后只是读取缓存操作的话,一般不会对数据库产生很大的问题,主要是涉及到数据的更新问题,数据库和缓存更新,就很容易出Redis 和 MySQL的数据一致性问题。
产生的问题其实不管我们是先删除缓存,再写库还是先写库,再删除缓存,都有可能会出现数据不一致的情况:
先删除缓存如果是删除Redis的缓存数据,在数据还没有写入MySQL数据库的时候,另一个线程就来读取缓存,就会发现这个缓存为空,然后会直接去MySQL数据库读取旧的数据并把数据写入缓存里面。这样,就会造成数据库更新后发现Redis和MySQL里面的数据不一致。
后删除缓存如果是先把数据写入了MySQL里面,正准备删除缓存的时候,突然写入数据库的线程发生异常,导致了缓存并没有被删除。这个时候,另一个线程就会直接读取到旧的缓存数据,这也会导致Redis和MySQL里面的数据不一致。
解决方案 延时双删策略这个方案主要是在写入数据的时候都进行缓存的删除操作,并且给它设置合理的超时时间。
具体操作:
1.先删除缓存 再写数据库
2.休眠几百毫秒 再次删除缓存
这么做的目的主要是为了确保这个请求结束后,有可能造成的缓存脏数据。这个方案最关键的其实还是给缓存设置过期时间,只要达到过期时间,缓存删除,如果后面还有读的请求,就会从数据库中读取新的值并且回填到缓存里面,这个是保证最终一致性的解决方案。
异步更新缓存这个方案是基于Mysql binlog的同步机制,在设计的更新的数据操作的时候,利用Mysql binlog进行增量的订阅消费,然后将消息发送给消息队列,再通过消息队列消费将增量数据更新到Redis上面。
具体操作:
1.读取Redis缓存 写Mysql
2.更新Redis缓存数据,Mysql 的数据操作都记录到binlog,再通过下次队列及时更新到Redis缓存上
这样的好处是一旦Mysql 中发生了新的写入、更新、删除等操作,丢会通过binlog把相关消息推送到Redis里面,Redis会根据binlog中的操作记录对Redis进行更新,而且这种方案和Mysql 的主从备份很相像,毕竟Mysql 的主从备份也是通过binlog来实现的数据的一致性的。
总结最后,在当前分布式高并发众多的场景下,解决高并发场景下数据一致性的方案有两种,分别是延时双删策略和异步更新缓存两种方案。