redis与数据库一致性策略
Redis与数据库的一致性问题:
我们常说的redis是非关系型的数据库,Mysql是关系型的数据库,很有可能我们修改的Mysql中数据在redis中同样存在一份备份,那么我们怎么保证redis与mysql数据库的数据一致性问题就是一个需要解决的问题。一般数据不一致的情形会出现在数据的写入的时候,
例如:
方案一:
先更新缓存在更新数据库
先删除缓存再更新数据库
方案二:
先更新数据库再更新缓存
先更新数据库再删除缓存
我们先来看先操作缓存的情况:
1.单个线程先删除缓存再操作数据库,没啥大问题
2.但是多线程下就会有时效性的问题;
线程1来到先删除缓存,然后在线程1向数据库更新数据时候,此时线程2来查询缓存发现缓存中没有,就会去查数据库,但是再线程1还未将新的数据写入数据库时候,线程2查询到老的数据,又把老的数据放到的缓存当中。
解决方案:可以在线程1修改完数据时候,再次删除以下redis中数据,就是我们常说的延迟双删模式,就是延迟几百ms后进行删除。
先操作数据库,再操作缓存:
直接来看多线程情况下:
线程1先更新数据库,后删除缓存,在线程1删除缓存前,线程2先查询到了缓存中的旧数据
注意:这种的方式我们可以保证数据的最终一致性,相比于第一种情况来说会好一点。但是也会存在一种情形,就是更新数据库成功了,但是删除缓存失败的情形,那么后期的每次读取缓存时候都会是脏数据,解决这种问题,我们采用的是删除重试机制,也就是可以采用MQ消息队列。解决的步骤如下:
1.首先删除数据库。
2.将需要删除的数据放到消息队列当中
3.线程可以不定时的去MQ中查看需要删除的数据
4,如果查询到就可以进行删除的重试机制
优点:消息队列可以保证写到队列的消息在成功消费前一定不会小时,采用的是手动ack机制.
缺点:会对代码的侵入性很强,我们需要改代码来消费MQ中数据
采用中间件技术:
Canal:是阿里开源的缓存一致性中间件,就是相当于一个Mysql的从服务器,好似Mycat中间件,当我们Mysql数据库开启一个二进制日志binlog时候,当业务代码对数据库更新时候,Canal会读取到更改的哪些数据二进制的日志,再将最终的数据放置到redis中保存数据的一致性。
总结:
redis缓存中的数据与数据库的数据只能保证最终一致性,我们基本不做强一致性,因为这样就会违背redis缓存引入的初中,因为redis引入就是保证一些时效性不强的数据尽量走缓存而非数据库,一般要求强一致性的数据我们均不放在缓存当中。