导致数据不一致性的场景:
场景一(查询):
高并发的时候,线程A redis未命中,去查询db,得到值1,还未回种redis,这时候db修改了,线程B redis未命中,查询db,得到值2,但线程B先存入redis,然后线程A存入redis,这时候redis的数据是值1,是条脏数据。
解决方案:
通过加锁解决,保证查询db和存入redis操作的原子性,或者用乐观锁,加个版本号或者时间戳,存入redis之前查下,但还是要保证查和存的原子性
场景二(更新):
先写入db,在删除缓存,可能出现db已经更新,但redis中未更新的情况,这时候redis命中后查到的数据就是旧数据,所以不行。
场景三(更新):
先删除缓存,再写入db。这其实也有并发问题:线程A是更新操作,先删除缓存,但还没写入db,这时候线程B来了,是个查询操作,发现缓存中没有数据,就去查db,但这时候线程A的写入操作还没完成,于是线程B查到了脏数据。
解决方案:
老外提出了一个缓存更新套路,名为Cache-Aside pattern。其中就指出
失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。
命中:应用程序从cache中取数据,取到后返回。
更新:先把数据存到数据库中,成功后,再让缓存失效。
这样的策略其实还是会出现并发问题:
假设这会有两个请求,一个请求A做查询操作,一个请求B做更新操作,那么会有如下情形产生
(1)缓存刚好失效
(2)请求A查询数据库,得一个旧值
(3)请求B将新值写入数据库
(4)请求B删除缓存
(5)请求A将查到的旧值写入缓存
此时,产生脏数据的原因:
请求B的写操作(3)要比请求A(2)的读操作耗时更短,才会出现(4)先于(5)
但是出现该情况的可能性是有多大呢,这边以读写分离为例,为啥会出现读写分离,读写分离的意义就是因为读操作比较快,耗资源少,不然要读写分离干啥?所以出现该场景的可能性太小了。
总结
redis和db的数据一致性理论上是不可能,如果真的对数据有强一致性的要求,就不应该放缓存里!!
网友评论