概述
在一次秒杀系统中接触到这个概念--Cache Aside Pattern
度娘之后,说下我的理解:
为什么要用缓存模式:
提升服务性能!!!而服务性能瓶颈往往都在DB,高并发情况下尤甚,我们知道数据库是持久化在硬盘上,而缓存往往是基于内存的,两个之间的读写性能不在一个量级,由此可见缓存带来的性能提升。
什么时候需要使用缓存?
1>需要频繁的查询数据库
2>极其消耗数据库性能的数据
比如:用户余额查询,商品库存查询,商品销量排行榜。。。
缓存的读写操作:
读操作流程:
(1)读取缓存中是否有相关数据
(2)如果缓存中有相关数据,则返回【这就是所谓的数据命中“hit”】
(3)如果缓存中没有相关数据,则从数据库读取相关数据【这就是所谓的数据未命中“miss”】,放入缓存中,再返回
缓存的命中率 = 命中缓存请求个数/总缓存访问请求个数 = hit/(hit+miss)
写操作流程:
这里涉及到Cache Aside Pattern的几个讨论点:
1>“淘汰缓存”还是“更新缓存”
毋庸置疑:淘汰缓存
什么是更新缓存:数据不但写入数据库,还会写入缓存
什么是淘汰缓存:数据只会写入数据库,不会写入缓存,只会把数据淘汰掉
若选择更新缓存,在并发写时,可能出现数据不一致。
在1和2两个并发写发生时,由于无法保证时序,此时不管先操作缓存还是先操作数据库,都可能出现:
(1)请求1先操作数据库,请求2后操作数据库
(2)请求2先set了缓存,请求1后set了缓存,导致,数据库与缓存之间的数据不一致。
若选择淘汰缓存,则只会增加一次Miss,不会产生脏读
2>缓存和数据库的操作时序
Cache Aside Pattern建议先操作数据库,再操作缓存
若先淘汰缓存再操作数据库:
在并发写时:
(1)写请求淘汰了缓存
(2)写请求操作了数据库(主从同步没有完成)
(3)读请求读了缓存(cache miss)
(4)读请求读了从库(读了一个旧数据)
(5)读请求set回缓存(set了一个旧数据)
(6)数据库主从同步完成
导致,数据库与缓存的数据不一致。
但是这里有个问题:
由于写数据库与淘汰缓存不能保证原子性,如果先操作数据库,再淘汰缓存,在原子性被破坏时:
(1)修改数据库成功了
(2)淘汰缓存失败了
还是会导致数据库与缓存的数据不一致。
究竟采用哪种时序呢?
对于一个不能保证事务性的操作,一定涉及“哪个任务先做,哪个任务后做”的问题,解决这个问题的方向是:
如果出现不一致,谁先做对业务的影响较小,就谁先执行。
所以,在不考虑并发的情况下,应首先考虑原子性,先淘汰缓存,在更新数据库
不考虑原子性的情况,可能会有并发写,这时应该先更新数据库,再淘汰缓存!
ps:总结
1>应该淘汰缓存而不是更新缓存,更新缓存在并发的时候可能带来数据的不一致 2>cache aside pattern 建议先操作数据库,再淘汰缓存,这样可能会导致一种情况,A请求更改了数据库,此时还没有淘汰缓存,这时B读请求读了缓存,读取到的数据就是脏数据,直到A请求淘汰了缓存数据才是正确的 3>若是先淘汰缓存后更新数据库,会导致写请求A淘汰缓存还没有来得及更新数据库,此时B读请求读了缓存,发现缓存中没有数据就去数据库读取,此时读取到的是旧值,然后把旧值存到redis中,导致之后的读请求都会读取到脏数据
最后
以上就是烂漫导师为你收集整理的Cache Aside Pattern(缓存模式)毋庸置疑:淘汰缓存的全部内容,希望文章能够帮你解决Cache Aside Pattern(缓存模式)毋庸置疑:淘汰缓存所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复