redis与数据库一致性策略

Redis与数据库的一致性问题:

我们常说的redis是非关系型的数据库,Mysql是关系型的数据库,很有可能我们修改的Mysql中数据在redis中同样存在一份备份,那么我们怎么保证redis与mysql数据库的数据一致性问题就是一个需要解决的问题。一般数据不一致的情形会出现在数据的写入的时候,

例如:

方案一:
     先更新缓存在更新数据库
     先删除缓存再更新数据库
方案二:
     先更新数据库再更新缓存
     先更新数据库再删除缓存

我们先来看先操作缓存的情况:

1.单个线程先删除缓存再操作数据库,没啥大问题

image-20230819144643681

2.但是多线程下就会有时效性的问题;
  线程1来到先删除缓存,然后在线程1向数据库更新数据时候,此时线程2来查询缓存发现缓存中没有,就会去查数据库,但是再线程1还未将新的数据写入数据库时候,线程2查询到老的数据,又把老的数据放到的缓存当中。

image-20230819145245098

解决方案:可以在线程1修改完数据时候,再次删除以下redis中数据,就是我们常说的延迟双删模式,就是延迟几百ms后进行删除。

先操作数据库,再操作缓存:

直接来看多线程情况下:

image-20230819150300365

线程1先更新数据库,后删除缓存,在线程1删除缓存前,线程2先查询到了缓存中的旧数据

注意:这种的方式我们可以保证数据的最终一致性,相比于第一种情况来说会好一点。但是也会存在一种情形,就是更新数据库成功了,但是删除缓存失败的情形,那么后期的每次读取缓存时候都会是脏数据,解决这种问题,我们采用的是删除重试机制,也就是可以采用MQ消息队列。解决的步骤如下:

1.首先删除数据库。
2.将需要删除的数据放到消息队列当中
3.线程可以不定时的去MQ中查看需要删除的数据
4,如果查询到就可以进行删除的重试机制

优点:消息队列可以保证写到队列的消息在成功消费前一定不会小时,采用的是手动ack机制.

缺点:会对代码的侵入性很强,我们需要改代码来消费MQ中数据

采用中间件技术:

Canal:是阿里开源的缓存一致性中间件,就是相当于一个Mysql的从服务器,好似Mycat中间件,当我们Mysql数据库开启一个二进制日志binlog时候,当业务代码对数据库更新时候,Canal会读取到更改的哪些数据二进制的日志,再将最终的数据放置到redis中保存数据的一致性。

image-20230819152513337

总结:

redis缓存中的数据与数据库的数据只能保证最终一致性,我们基本不做强一致性,因为这样就会违背redis缓存引入的初中,因为redis引入就是保证一些时效性不强的数据尽量走缓存而非数据库,一般要求强一致性的数据我们均不放在缓存当中。

posted @ 2023-08-25 17:12  LycCj  阅读(85)  评论(0编辑  收藏  举报