mysql和redis如何保证数据库一致性

如果对于小公司的单机服务器来说在更新和删除mysql数据的同时对redis缓存进行更新或者删除就行,一般有两个选择,例如:

  1. 先更新MySQL,后删除(或更新)Redis
  2. 先删除(或更新)Redis,后更新MySQL

但是不管使用其中哪种方式,都存在两个可能的问题:

  1. 由于第一步与第二步并不是原子的,中间会存在较短的时间间隔,如果间隔时间内有请求到达,就可能会访问到不一致的数据。
  2. 可能存在做完第一步,第二步还没来得及做,系统就发生异常的情况;这就会导致MySQL与Redis的数据不一致。

解决方案:

延迟双删策略

延迟双删策略是分布式系统中数据库存储和缓存数据保持一致性的常用策略,但它不是强一致。其实不管哪种方案,都避免不了Redis存在脏数据的问题,只能减轻这个问题,要想彻底解决,得要用到同步锁和对应的业务逻辑层面解决。

在业务程序运行时,统计业务逻辑执行读数据和写缓存的操作时间,以此为基础来进行估算。因为这个方案会在第一次删除缓存值后,延迟一段时间再次进行删除,所以称为“延迟双删”。

先进行缓存清除,再执行update,最后(延迟N秒)再执行缓存清除。进行两次删除,且中间需要延迟一段时间

RedisUtils.del(key);// 先删除缓存    
updateDB(user);// 更新db中的数据    
Thread.sleep(N);// 延迟一段时间,在删除该缓存key    
RedisUtils.del(key);// 先删除缓存

上述中(延迟N秒)的时间要大于一次写操作的时间。原因:如果延迟时间小于写入redis的时间,会导致请求1清除了缓存,但是请求2缓存还未写入的尴尬。。。

延迟双删策略只是一种同步数据库与缓存的手段,在系统并发量不高的情况下可以使用这种方式解决,但是很难控制第二次删除时需要延迟的时间段。

通过MQ异步更新同步数据到redis

这种方式是在更新db操作的时候,把对应需要更新的数据(增删改)通过MQ消息队列的方式发布到消息队列服务器,MQ客户端订阅该消息同步更新到redis缓存,但是这种方式要保证消息队列的顺序性,这样的话,在高并发上也会存在一定延迟。

通过canal组件订阅数据库binlog服务

这种方式是,通过订阅mysql的binlog日志,把数据库增删改日志转换成json数据,通过MQ发布消息,客户端订阅该消息同步更新到redis缓存,这种方式能很好的解决高并发和分布式服务更新数据带来的mysql和redis不一致的情况,同时使用数据库客户端通过sql手动更新的数据也能同步到redis。

猜你喜欢

转载自blog.csdn.net/lwpoor123/article/details/130240148