这里是Z哥的个人公众号
每周五早8点 按时送达
当然了,也会时不时加个餐~
我的第「78」篇原创敬上
今天来加个餐,紧急纠正一个错误。先和大家说一声抱歉:D
昨晚睡觉前,惯例打开「订阅号助手」回复一些留言。有一位小伙伴提了一个问题,问题来源于《分布式系统关注点》专题的第17篇《先写DB还是「缓存」?》中。
下面就是提出问题的这位小伙伴,@L。这次非常感谢他。
文章的原文是这样的:
-------------原文开始-------------
先DB再缓存
数据库操作成功,缓存操作的失败的情况该怎么解?(主要在用到redis,memcached这种进程外缓存的时候,由于网络因素,失败的可能性大增)
办法也是有的,在操作数据库的时候带一个事务,如果缓存操作失败则事务回滚。大致的代码意思如下:
begin trans var isDbSuccess = write db; if(isDbSuccess){ var isCacheSuccess = write cache; if(isCacheSuccess){ return success; } else{ rollback db; return fail; } } else{ return fail; } catch(Exception ex){ rollback db; }
end trans
如此一来就万无一失了吗?并不是。除了由于事务的引入,增加了数据库的压力之外,在极端场景下可能会出现rollback db失败的情况。是不是很头疼?
解决这个问题的方式就是write cache的时候做delete操作,而不是set操作。如此一来,用多一次cache miss的代价来换rollback db失败的问题。
就像图上所示,哪怕rollback失败了,通过一次cache miss重新从db中载入旧值。
-------------原文结束-------------
如果没看出来问题或者已经遗忘的小伙伴可以去原文地址看下:分布式系统关注点——先写DB还是「缓存」?
也不知道当时咋了,脑子昏了。其实这里的「rollback db失败」表述应该换成「commit db失败」。
而且顺带图也画错了……
正确逻辑图应该是这样。
虽然数据库操作有XA规范的保证,但是由于需要进行二次确认,而确认又需要经过网络,所以在网络不稳定的情况下,的确会出现commit失败的情况。
这个时候delete的好处就出来了。
假如真的commit失败了,最多就是从db里再捞一份旧数据出来。
而如果使用set的话,缓存中就会存在脏数据了,必须得再多做一次set,将旧数据set回去。并且,这个操作还有可能出现失败。
好了,这次要说的就那么多,周五早上8点再见吧:D
推荐阅读:
分布式系统关注点——360°的全方位监控
8个月打磨,一份送给程序员的「分布式系统」合集
原创不易,如果你觉得这篇文章还不错,就「在看」或者「分享」一下吧。鼓励我的创作 :)
如果有希望我写一下什么主题的话,欢迎在后台给我留言哦~
如果你有关于软件架构、分布式系统、产品、运营的困惑
可以试试点击「阅读原文」