从“熔断”和“降级”说起

原文链接:http://www.dubby.cn/detail.html?id=9053

随着微服务的兴起,很多名词都不断的提出,我想大家都听过一些,但是很多其实并不了解,今天起来看到了DD分享的《白话:服务降级与熔断的区别》,觉得分享的非常好,通俗易懂,可是我心中想要的东西不止这些,所以这里献丑,分享一下我的想法。就从“熔断”和“降级”说起吧。

什么是熔断?

其实很多时候,看到他真正的原词,你就会明白他是个什么东西了,因为作者总是希望你们能理解他的意图,所以命名时总会挑选一个最接近的词。

一个人可以拥有世界上最伟大的思想——完全与众不同,别出心裁,但这个人必须能够说服足够多的人理解并接受他的思想,如果不能,那么他的伟大思想也就不足为奇了。 ——格雷戈里 伯恩斯

我们先看一下他的英文,circuit-breaker。有过物理知识,额,就算你没有物理知识也应该明白家里有个熔断器(断路器),就是防止回路里的电流过大,引起火灾甚至更大的事故。所以当电流打到一定的程度的时候,就自行熔断那个保险丝,切断电流。那么什么样的电流算大呢?这个值当然是经过精心考量的,不能太小,不然玩把LOL就断电了,也不能太大,不然消防都来了,断路器还没熔断,我要你有何用?

这其实就是微服务中的熔断器的思想。当一个系统中的流量已经不正常的时候,为了避免引起更大的灾难,及时切断不正常的流量。虽然思想和上面类似,但是细节不是完全相同,这里简单介绍一下。

家用的断路器是为了保护电路,防止火灾,那么微服务中的断路器是为了保护什么呢?

正常情况下,微服务的请求流是这样的:

从“熔断”和“降级”说起

你的一个请求,会由很多服务共同完成,比如:下单服务,要依赖账号服务获取用户信息,商品服务获取仓库存货,配送服务生成运货单,支付服务完成支付,风控服务拦截异常用户,等等。现在是一切正常,大家相安无事,和谐社会。

这时候,风控服务出问题了,开始超时,以前是100ms就可以返回,现在需要10000ms,于是,情况变成了这个样子:

从“熔断”和“降级”说起

似乎也没什么问题嘛,不就是一个用户的请求返回的有点慢了,没啥大问题。可是,事情不止如此:

从“熔断”和“降级”说起

下一个用户请求也会超时返回,下下个也是……直到所有的业务线程都被堵塞住,啥?听不懂我在说啥?我们可把tomcat这类的servlet容器想象成一家医院,你来到医院挂号,然后每个一个医生会处理病人的病情,这里的医生就是用户线程,如果医院停电了,那么所有需要用到电器的病人都要等着供电恢复。假设有10个医生,来了10个需要用到电器的病人,这10个病人占据了10个医生的时间,后面陆续道来的病人没办法治疗,可是有的病人根本不需要用到电啊,没办法,他们只能排队,排到他们病发生亡或者供电恢复,或者前面的10个病人不愿意干等着电恢复主动离开。

这就是雪崩

“为什么雪崩这个词是在微服务出现之后才会出现呢?按照你的描述,不是每个系统都可能出现吗?”
没错,每个系统都可能出现,只是因为在微服务下,服务和服务之间拆分的很细,服务和服务之间依赖关系就不可避免的变得复杂,而这种跨应用,跨机器,甚至跨机房的服务调用稳定性要远远低于本地方法调用(服务不可用、超时等情况),所以,这个话题才变得如此敏感。

异常流量本来只是小范围的故障,但如果继续下去,可能会引发更大范围的故障,严重时,整个系统都不可用。熔断器在这里就可以大展身手了,直接熔断那些需要注射器的病人,也就是说,“不好意思,这位先生,现在停电了,我们现在没条件给您治病,所以请您赶快离开,不要浪费我们珍贵的医生资源了”(当然,可以说的更得体一些)。这样,就算停电了,医院还是可以处理一些病人,不至于真的停业。

我们不妨多思考一下,“怎么可以判断是停电了呢?”“又怎么判断电已经恢复了呢?”毕竟不能一直不治疗那些需要用到电器的病人啊,而且如果误判停电,那对那些需要电器的病人是不公平的。
本文只是科普,并不打算解释熔断器的原理,读者如果感兴趣,可以阅读后续文章(如果我还写的话)。

什么是降级?

我们继续上面的那个话题。我们医院的口号是,“让天下没有难治的病”!所以,就算停电,我们也决不允许病人得不到治疗,病情加重恶化。所以,我们准备了Plan B(后手准备)。

如果在使用电器的时候,发现没电了,没关系。我们还有一个老中医!精通:望闻问切,针灸拔罐推拿。这时候就把这个病人送到这个老中医那里去,让他来处理。

从“熔断”和“降级”说起

这样,因为我们的后手准备,就算停电了,也不怕,还是可以赚到这份钱,呸呸,治好这个病人。

“有老中医,为啥还要西医呢?老中医永远不依赖电,不是更稳定吗,我们要不要直接废弃西医,改用中医呢?”
年轻人,首先不是所有人都接受的中医这套理论的;其次,老中医很老了,看病很慢的,只用老中医,医院赚钱就会少很多,呸呸,就会少帮助很多病人;老中医还可能治错病(这里没有任何偏见,只是为了举例子);等等……所以,西医才是主流,明白了吧。

我还想多说几句

要想成为一个优秀的医生,并非一朝一夕,而是长时间的苦练。举个例子,来了一个病人,一看,感冒了,开个999感冒灵就好了,可是这个药没了(这也是一种依赖资源的不可用):

  • 普通医生:看一下药物查询系统,“哎呀,我们这个药没了,这个钱我们没法赚了,你回去吧。”;
  • 有经验的医生:看了一下系统,库存里没有999感冒灵了,别着急,过几分钟再看一下,还是没有,没事,过几分钟再看一下,这样反复看个几次,如果运气好,正好补货了,这个钱咱不就赚到了吗,你说对不,当然啦,如果试了好几次都还没有,就别浪费时间了,让他走吧;
  • 经验丰富的医生:他已经不仅仅满足于能不能拿到药了,他有着更高的追求,那就是效率!如何最快的完成这一单,毕竟我们也是靠拿提成的,单子越多,收入就越高啊。所以,每次拿药,都是用系统A,系统B,系统C,系统D同时查询,哪个最快返回查询结果,就知道有没有药了,这样,偶尔一两个系统出故障或者死机了,都不能拖慢我赚钱的步伐;
  • 医生中的老司机:就算药没有,也假装治好了这个病人,毕竟提成只看完成单数,能蒙混过关就行。

其实这就是对依赖服务的调用方式,常见的有:

  • Failover:失败自动切换,当出现失败,重试其它服务器。
  • Failfast:快速失败,只发起一次调用,失败立即报错。
  • Failsafe:失败安全,出现异常时,直接忽略。
  • Failback:失败自动恢复,后台记录失败请求,定时重发。
  • Forking:并行调用多个服务器,只要一个成功即返回。
  • Broadcast:广播调用所有提供者,逐个调用,任意一台报错则报错。

微信扫码关注订阅号,获取更多精彩内容
从“熔断”和“降级”说起