纠正一个错误,分布式系统关注点第17篇

今天来纠正一个错误。先和大家说一声抱歉: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



原创文章,转载请注明本文链接: https://zacharyfan.com/archives/787.html

关于作者:张帆(Zachary,个人微信号:Zachary-ZF)。坚持用心打磨每一篇高质量原创。欢迎扫描二维码~

微信公众号

定期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些思考。

如果你是初级程序员,想提升但不知道如何下手。又或者做程序员多年,陷入了一些瓶颈想拓宽一下视野。欢迎关注我的公众号「跨界架构师」,回复「技术」,送你一份我长期收集和整理的思维导图。

如果你是运营,面对不断变化的市场束手无策。又或者想了解主流的运营策略,以丰富自己的“仓库”。欢迎关注我的公众号「跨界架构师」,回复「运营」,送你一份我长期收集和整理的思维导图。

Leave a Reply

发表评论

电子邮件地址不会被公开。 必填项已用*标注

ZacharyFan.com © 2019 | WordPress Theme: BlogGem by TwoPoints.