运用缓存的时分,咱们需要关注Redis与DB数据的一致性。假如Redis缓存与DB数据不一致,就可能导致用户一直只能获取到数据错误的缓存,严重影响用户体会。那怎样让Redis与DB数据一致性呢?
怎样确保数据库和缓存的一致性
首要咱们来讨论几个更新时的计划吧,我将从各个计划进行剖析,让你知道这些计划会呈现的问题,并且终究会得出怎样确保数据库和缓存的一致性。(运用的图解皆来源于网络)
先更新缓存再更新数据库
咱们来举个比如,在并发状况下,恳求A 和 恳求B 两个恳求,一起更新同一个数据时,什么样的履行流程会导致数据不一致。
如图,假如恳求A先更新了缓存(值为1),恳求B在它之后也更新了缓存(值为2),然后恳求B持续履行,把数据库更新为2,之后恳求A也持续履行,把数据库更新为1。
此时,缓存的值为2,数据库的值为1。很显着,呈现了缓存不一致的状况。那咱们再换一种思路试试看?
先更新数据库再更新缓存
咱们也来剖析一下这种状况下,什么样的顺序会呈现缓存不一致。
恳求A把数据库数据更新为1,之后恳求B把数据库更新为2。接着,缓存被恳求B更新为2,缓存再被恳求A更新为1。
很显着,这种思路也会呈现数据不一致的状况。至此,一起更新缓存和数据库的计划,都显着呈现了数据不一致的现象,那还有什么其他的思路能够用吗?
有的,更新数据库的一起删去缓存,当缓存未射中时,查询缓存。那咱们依照这个思路来进行剖析。
先删去缓存再更新数据库
如图,咱们能够剖分出,恳求A先删去了缓存,恳求B在其之后发现缓存未射中然后就去读取数据库更新缓存,最后恳求A再更新了数据库。此时缓存为20,数据库为21,呈现了不一致。实践上,只有数据库更新后,再被查询数据时,才会是更新后的数据。依照这个思路,又引出了另一种战略。
先更新数据库再删去缓存
恳求A发现缓存没有射中,然后去恳求数据库,之后恳求B更新了数据库并删去了缓存,恳求A再将数据写入缓存。能够发现,依旧是有不一致的状况产生。
前面四种战略应该怎样挑选
从上面的剖析来看,四种战略都是会有不一致的现象产生的。虽然是这样的没错,可是先更新数据库再删去缓存的不一致现象产生的概率会小一些,因为数据库更新是没有缓存写入快的,所以在实践中很难呈现恳求 B 已经更新了数据库并且删去了缓存,恳求 A 才更新完缓存的状况。
所以先更新数据库再删去缓存是能够在一定程度上确保一致性的,关于可能产生的不一致状况,咱们能够给数据加上过期时间作为对一致性的兜底。
不过这也仅仅是在咱们的操作全部履行成功的状况下才干确保一致性,在实践状况中,由于网络等因素,咱们的操作是可能会失利的,而更新数据库和删去缓存是两个操作(非原子),所以当删去缓存失利的时分,一致性就无法确保了。
可是在一般的事务上,这四种战略已经是足够运用了,一般运用第四种。关于不同场景下,还是有不同的挑选,并不一定无脑挑选第四种。当你的事务是关于缓存射中率要求高的事务时,能够采用先更新数据库,再更新缓存,不过咱们必须引进一些其他办法来减少不一致产生的状况。例如:
- 在更新完缓存时,给缓存加上较短的过期时间,这样即便呈现缓存不一致的状况,缓存的数据也很快会保持一致。
在其他状况下,就无脑运用先更新数据库再更新缓存就行。
有没有真实能够确保一致性的计划
先说定论,是有的,可是会愈加杂乱。
首要咱们要明确:其实不管是先操作数据库,还是先操作缓存,只需删去缓存操作失利都会呈现数据一致的问题。
问题原因知道了,该怎样处理呢?有两种办法:
1.重试机制
咱们能够引进音讯行列,将第二个操作(删去缓存)要操作的数据加入到音讯行列,由顾客来操作数据。
重试机制的大致步骤:
- 写恳求更新数据库
- 缓存因为某些原因,删去失利
- 把删去失利的key放到音讯行列
- 消费音讯行列的音讯,获取要删去的key
- 重试删去缓存操作
坏处是形成大量事务代码侵略。不过这个是小事情。
2.订阅Mysql binlog
先更新数据库,再删缓存的战略的第一步是更新数据库,那么更新数据库成功,就会产生一条变更日志,记录在 binlog 里。
于是咱们就能够通过订阅 binlog 日志,拿到具体要操作的数据,然后再履行缓存删去,阿里巴巴开源的 Canal 中间件就是根据这个完成的。
这个办法我是在网上偶然看见的,还没有尝试过,有兴趣的小伙伴能够深化去了解下。
希望我的文章对大家学习缓存与DB一致性有所协助。