Redis⾼级项⽬实战!mysql基础教程⽇本西泽梦路.pdf
前⾔
我朋友也是个写了四年Java代码的程序员,跟⼥友已经恋爱多年,最近突然结婚了。
他结婚以前,换了⼀家公司,咱俩就好久没见过⾯了。刚好今天出门办事碰上了,了⼀家店坐⼀起喝酒聊天。
我聊天时打趣他:“亏得你⼩⼦运⽓好,还能娶到⽼婆。咱们这⼀⾏,不是加班就是加班,天天就是和代码过⽇⼦。”
朋友说:“做这⼀⾏也就⼯资看着⾼点,确实是每天都累死累活。我还不是⼀样的加班,都没时间陪⽼婆!”
跟着⼜聊到了⼯作,朋友听到我还在写业务代码⾮常意外:“你还在原来的公司做?我跳槽后就开始学习分布式架构、微服务、JVM调优、并发编程、SpringCloud等,虽然过程很是艰⾟;但是后⾯接⼿做了⼏个⼤项⽬后就升职了,薪⽔也涨了不少、不然就凭以前那点⼯资,哪敢结婚买房。”
我于是问了问他的⽉薪税后28K,不由得⼼底⼀凉…瞬间觉得最该同情的是⾃⼰。同时我也有点⼼动了,谁不想升职加薪呢?
我和朋友倒起了苦⽔:⾃⼰在公司⼲了这么久了,⼯资也没有提升,每天都是写业务代码,技术也得不到提⾼,很焦虑。我也想⾃⼰去学点东西,增加⾃⼰的价值,就是遇到瓶颈,不知道从哪⼊⼿。
他⼀听就说:“现在都说互联⽹寒冬,其实⽆⾮就是你上错了车,且穿的少(技术),要是你上对车,⾃⾝能⼒够强,公司换掉的代价⼤,怎么可能会被裁掉,都是淘汰末端的Coder⽽已!
你现在就是缺少进阶Java中⾼级的机会,去深⼊去学习下数据结构算法、JVM调优、分布式架构设计等等;不然你在市场上没有核⼼竞争⼒,根本拿不到⾼薪!时间就是⾦钱,我向你推荐⼀套免费精品Java⾼级教程,保证你学了以后保证薪资上升⼀个台阶。”
如何保证缓存和数据库⼀致性
说了这么多缓存的必要性,那么使⽤缓存是不是就是⼀个很简单的事情了呢,我之前也⼀直是这么觉
得的,直到遇到了需要缓存与数据库保持强⼀致的场景,才知道让数据库数据和缓存数据保持⼀致性是⼀门很⾼深的学问。
从远古的硬件缓存,操作系统缓存开始,缓存就是⼀门独特的学问。这个问题也被业界探讨了⾮常久,争论⾄今。我翻阅了很多资料,发现其实这是⼀个权衡的问题。值得好好讲讲。
以下的讨论会引⼊⼏⽅观点,我会跟着观点来写代码验证所提到的问题。
不更新缓存,⽽是删除缓存
⼤部分观点认为,做缓存不应该是去更新缓存,⽽是应该删除缓存,然后由下个请求去去缓存,发现不存在后再读取数据库,写⼊缓存。
观点引⽤:《分布式之数据库和缓存双写⼀致性⽅案解析》孤独烟
原因⼀:线程安全⾓度
同时有请求A和请求B进⾏更新操作,那么会出现
(1)线程A更新了数据库
(2)线程B更新了数据库
(3)线程B更新了缓存
(4)线程A更新了缓存
这就出现请求A更新缓存应该⽐请求B更新缓存早才对,但是因为⽹络等原因,B却⽐A更早更新了缓存。这就导致了脏数据,因此不考虑。
原因⼆:业务场景⾓度
有如下两点:
(1)如果你是⼀个写数据库场景⽐较多,⽽读数据场景⽐较少的业务需求,采⽤这种⽅案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。
(2)如果你写⼊数据库的值,并不是直接写⼊缓存的,⽽是要经过⼀系列复杂的计算再写⼊缓存。那么,每次写⼊数据库后,都再次计算写⼊缓存的值,⽆疑是浪费性能的。显然,删除缓存更为适合。
其实如果业务⾮常简单,只是去数据库拿⼀个值,写⼊缓存,那么更新缓存也是可以的。但是,淘汰缓存操作简单,并且带来的副作⽤只是增加了⼀次cache miss,建议作为通⽤的处理⽅式。
先操作缓存,还是先操作数据库
那么问题就来了,我们是先删除缓存,然后再更新数据库,还是先更新数据库,再删缓存呢?
先来看看⼤佬们怎么说。
《【58沈剑架构系列】缓存架构设计细节⼆三事》58沈剑:
对于⼀个不能保证事务性的操作,⼀定涉及“哪个任务先做,哪个任务后做”的问题,解决这个问题的⽅向是:如果出现不⼀致,谁先做对业务的影响较⼩,就谁先执⾏。
假设先淘汰缓存,再写数据库:第⼀步淘汰缓存成功,第⼆步写数据库失败,则只会引发⼀次Cache miss。
假设先写数据库,再淘汰缓存:第⼀步写数据库操作成功,第⼆步淘汰缓存失败,则会出现DB中是新数据,Cache中是旧数据,数据不⼀致。滚动条样式库
沈剑⽼师说的没有问题,不过没完全考虑好并发请求时的数据脏读问题,让我们再来看看孤独烟⽼师《分布式之数据库和缓存双写⼀致性⽅案解析》:
先删缓存,再更新数据库
该⽅案会导致请求数据不⼀致
同时有⼀个请求A进⾏更新操作,另⼀个请求B进⾏查询操作。那么会出现如下情形:
(1)请求A进⾏写操作,删除缓存
(2)请求B查询发现缓存不存在
(3)请求B去数据库查询得到旧值
(4)请求B将旧值写⼊缓存practice读
(5)请求A将新值写⼊数据库
上述情况就会导致不⼀致的情形出现。⽽且,如果不采⽤给缓存设置过期时间策略,该数据永远都是脏数据。
所以先删缓存,再更新数据库并不是⼀劳永逸的解决⽅案,再看看先更新数据库,再删缓存这种⽅案怎么样?
先更新数据库,再删缓存这种情况不存在并发问题么?
不是的。假设这会有两个请求,⼀个请求A做查询操作,⼀个请求B做更新操作,那么会有如下情形产⽣
(1)缓存刚好失效
(2)请求A查询数据库,得⼀个旧值
(3)请求B将新值写⼊数据库
(4)请求B删除缓存
(5)请求A将查到的旧值写⼊缓存
ok,如果发⽣上述情况,确实是会发⽣脏数据。
然⽽,发⽣这种情况的概率⼜有多少呢?
发⽣上述情况有⼀个先天性条件,就是步骤(3)的写数据库操作⽐步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。可是,⼤家想想,数据库的读操作的速度远快于写操作的(不然做读写分离⼲嘛,做读写分离的意义就是因为读操作⽐较快,耗资源少),因此步骤(3)耗时⽐步骤(2)更短,这⼀情形很难出现。
先更新数据库,再删缓存依然会有问题,不过,问题出现的可能性会因为上⾯说的原因,变得⽐较低!
(补充说明:我⽤了“先更新数据库,再删缓存”且不设过期时间策略,会不会有问题呢?由于先缓存和更新数据库不是原⼦的,如果更新了数据库,程序歇逼,就没删缓存,由于没有过期策略,就永远脏数据了。)
所以,如果你想实现基础的缓存数据库双写⼀致的逻辑,那么在⼤多数情况下,在不想做过多设计,增加太⼤⼯作量的情况下,请先更新数据库,再删缓存!
我⾮要数据库和缓存数据强⼀致怎么办
oracle school那么,如果我⾮要保证绝对⼀致性怎么办,先给出结论:elasticsearch mysql
没有办法做到绝对的⼀致性,这是由CAP理论决定的,缓存系统适⽤的场景就是⾮强⼀致性的场景,所以它属于CAP中的AP。
所以,我们得委曲求全,可以去做到BASE理论中说的最终⼀致性。
最终⼀致性强调的是系统中所有的数据副本,在经过⼀段时间的同步后,最终能够达到⼀个⼀致的状
态。因此,最终⼀致性的本质是需要系统保证最终数据能够达到⼀致,⽽不需要实时保证系统数据的强⼀致性
⼤佬们给出了到达最终⼀致性的解决思路,主要是针对上⾯两种双写策略(先删缓存,再更新数据库/先更新数据库,再删缓存)导致的脏数据问题,进⾏相应的处理,来保证最终⼀致性。
缓存延时双删
问:先删除缓存,再更新数据库中避免脏数据?
答案:采⽤延时双删策略。
上⽂我们提到,在先删除缓存,再更新数据库的情况下,如果不采⽤给缓存设置过期时间策略,该数据永远都是脏数据。
mysql入门基础教程那么延时双删怎么解决这个问题呢?
(1)先淘汰缓存
(2)再写数据库(这两步和原来⼀样)
(3)休眠1秒,再次淘汰缓存
这么做,可以将1秒内所造成的缓存脏数据,再次删除。
那么,这个1秒怎么确定的,具体该休眠多久呢?
针对上⾯的情形,读者应该⾃⾏评估⾃⼰的项⽬的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上,加⼏百ms即可。这么做的⽬的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。
如果你⽤了mysql的读写分离架构怎么办?
ok,在这种情况下,造成数据不⼀致的原因如下,还是两个请求,⼀个请求A进⾏更新操作,另⼀个请求B进⾏查询操作。
(1)请求A进⾏写操作,删除缓存
(2)请求A将数据写⼊数据库了,
(3)请求B查询缓存发现,缓存没有值
(4)请求B去从库查询,这时,还没有完成主从同步,因此查询到的是旧值
(5)请求B将旧值写⼊缓存
(6)数据库完成主从同步,从库变为新值
上述情形,就是数据不⼀致的原因。还是使⽤双删延时策略。只是,睡眠时间修改为在主从同步的延时时间基础上,加⼏百ms。
采⽤这种同步淘汰策略,吞吐量降低怎么办?
ok,那就将第⼆次删除作为异步的。⾃⼰起⼀个线程,异步删除。这样,写的请求就不⽤沉睡⼀段时间后了,再返回。这么做,加⼤吞吐量。
所以在先删除缓存,再更新数据库的情况下,可以使⽤延时双删的策略,来保证脏数据只会存活⼀段时间,就会被准确的数据覆盖。
在先更新数据库,再删缓存的情况下,缓存出现脏数据的情况虽然可能性极⼩,但也会出现。我们依然可以⽤延时双删策略,在请求A对缓存写⼊了脏的旧值之后,再次删除缓存。来保证去掉脏缓存。
vs2017调试窗口怎么弄出来总⽬录展⽰
该笔记共⼋个节点(由浅⼊深),分为三⼤模块。
⾼性能。 秒杀涉及⼤量的并发读和并发写,因此⽀持⾼并发访问这点⾮常关键。该笔记将从设计数据的动静分离⽅案、热点的发现与隔离、请求的削峰与分层过滤、服务端的极致优化这4个⽅⾯重点介绍。
⼀致性。 秒杀中商品减库存的实现⽅式同样关键。可想⽽知,有限数量的商品在同⼀时刻被很多倍的请求同时来减库存,减库存⼜分
为“拍下减库存”“付款减库存”以及预扣等⼏种,在⼤并发更新的过程中都要保证数据的准确性,其难度可想⽽知。因此,将⽤⼀个节点来专门讲解如何设计秒杀减库存⽅案。
⾼可⽤。 虽然介绍了很多极致的优化思路,但现实中总难免出现⼀些我们考虑不到的情况,所以要保证系统的⾼可⽤和正确性,还要设计⼀个PlanB来兜底,以便在最坏情况发⽣时仍然能够从容应对。笔记的最后,将带你思考可以从哪些环节来设计兜底⽅案。
篇幅有限,⽆法⼀个模块⼀个模块详细的展⽰(这些要点都收集在了这份《⾼并发秒杀顶级教程》⾥),觉得有需要的码友们,⿇烦各位转发⼀下(可以帮助更多的⼈看到哟!)
[外链图⽚转存中…(img-cPTRLWxl-1621049363140)] [外链图⽚转存中…(img-Qw0GJYkf-1621049363143)]

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。