伴随着微服务架构被宣传得如火如荼,一些概念也被推到了我们面前(管你接受不接受),其实大多数概念以前就有,但很少被提的这么频繁(现在好像不提及都不好意思交流了)。想起有人总结的一句话,微服务架构的特点就是:“一解释就懂,一问就不知,一讨论就吵架”。

其实对老外的总结能力一直特别崇拜,Kevin Kelly、Martin Fowler、Werner Vogels……,都是著名的“演讲家”。正好这段时间看了些微服务、容器的相关资料,也在我们新一代产品中进行了部分实践,回过头来,再来谈谈对一些概念的理解。

一、“服务熔断”和“服务降级

今天先来说说“服务熔断”和“服务降级”。为什么要说这个呢,因为我很长时间里都把这两个概念同质化了,不知道这两个词大家怎么理解,一个意思or有所不同?现在的我是这么来看的:

两个示例:

示例1:

故事的背景是这样的:由于小强在工作中碰到一些问题,于是想请教一下业界大牛小壮。于是发生了下面的两个场景:

小强在拿起常用手机拨号时发现该手机没有能够拨通,所以就拿出了备用手机拨通了某A的电话,这个过程就叫做降级(主逻辑失败采用备用逻辑的过程)。

由于每次小壮的解释都属于长篇大论,不太容易理解,所以小强每次找小壮沟通的时候都希望通过常用手机来完成,因为该手机有录音功能,这样自己可以慢慢消化。由于上一次的沟通是用备用电话完成的,小强又碰到了一些问题,于是他又尝试用常用电话拨打,这一次又没有能够拨通,所以他不得不又拿出备用手机给某A拨号,就这样连续的经过了几次在拨号设备选择上的“降级”,小强觉得短期内常用手机可能因为运营商问题无法正常拨通了,所以,再之后一段时间的交流中,小强就不再尝试用常用手机进行拨号,而是直接用备用手机进行拨号,这样的策略就是熔断(常用手机因短期内多次失败,而被暂时性的忽略,不再尝试使用)

示例2:

  1. 在股票市场,熔断这个词大家都不陌生,是指当股指波幅达到某个点后,交易所为控制风险采取的暂停交易措施。相应的,服务熔断一般是指软件系统中,由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,从而采用的一种保护措施,所以很多地方把熔断亦称为过载保护。
  2. 大家都见过女生旅行吧,大号的旅行箱是必备物,平常走走近处绰绰有余,但一旦出个远门,再大的箱子都白搭了,怎么办呢?常见的情景就是把物品拿出来分分堆,比了又比,最后一些非必需品的就忍痛放下了,等到下次箱子够用了,再带上用一用。而服务降级,就是这么回事,整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来。

所以从上述分析来看,两者其实从有些角度看是有一定的类似性的:

  1. 目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;
  2. 最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用;
  3. 粒度一般都是服务级别,当然,业界也有不少更细粒度的做法,比如做到数据持久层(允许查询,不允许增删改);
  4. 自治性要求很高,熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段;

而两者的区别也是明显的:

  1. 触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
  2. 管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)
  3. 实现方式不太一样,这个区别后面会单独来说;

二、熔断器的状态机

  当然这只是我个人对两者的理解,外面把两者归为完全一致的也不在少数,或者把熔断机制理解为应对降级目标的一种实现也说的过去,可能“一讨论就吵架”也正是这个原因吧! 概念算是说完了,避免空谈,我再总结下对常用的实现方法的理解。对于这两个概念,号称支持的框架可不少,Hystrix当属其中的佼佼者。 先说说最裸的熔断器的设计思路,下面这张图大家应该不陌生(我只是参考着又画了画),简明扼要的给出了好的熔断器实现的三个状态机

  1. Closed:熔断器关闭状态,调用失败次数积累,到了阈值(或一定比例,默认是50%)则启动熔断机制;
  2. Open:熔断器打开状态,此时对下游的调用都内部直接返回错误,不走网络,但设计了一个时钟选项,默认的时钟达到了一定时间(这个时间一般设置成平均故障处理时间,也就是MTTR),到了这个时间,进入半熔断状态;
  3. Half-Open:半熔断状态,允许定量的服务请求,如果调用都成功(或一定比例)则认为恢复了,关闭熔断器,否则认为还没好,又回到熔断器打开状态;

那Hystrix,作为Netflix开源框架中的最受喜爱组件之一,是怎么处理依赖隔离,实现熔断机制的呢,他的处理远比我上面说个实现机制复杂的多,一起来看看核心代码吧,我只保留了代码片段的关键部分:

  1. public abstract class HystrixCommand<R> extends AbstractCommand<R> implements HystrixExecutable<R>, HystrixInvokableInfo<R>, HystrixObservable<R> {
  2. protected abstract R run() throws Exception;
  3. protected R getFallback() {
  4. throw new UnsupportedOperationException("No fallback available.");
  5. }
  6. @Override
  7. final protected Observable<R> getExecutionObservable() {
  8. return Observable.defer(new Func0<Observable<R>>() {
  9. @Override
  10. public Observable<R> call() {
  11. try {
  12. return Observable.just(run());
  13. } catch (Throwable ex) {
  14. return Observable.error(ex);
  15. }
  16. }
  17. });
  18. }
  19. @Override
  20. final protected Observable<R> getFallbackObservable() {
  21. return Observable.defer(new Func0<Observable<R>>() {
  22. @Override
  23. public Observable<R> call() {
  24. try {
  25. return Observable.just(getFallback());
  26. } catch (Throwable ex) {
  27. return Observable.error(ex);
  28. }
  29. }
  30. });
  31. }
  32. public R execute() {
  33. try {
  34. return queue().get();
  35. } catch (Exception e) {
  36. throw decomposeException(e);
  37. }
  38. }
HystrixCommand是重重之重,在Hystrix的整个机制中,涉及到依赖边界的地方,都是通过这个Command模式进行调用的,显然,这个Command负责了核心的服务熔断和降级的处理,子类要实现的方法主要有两个:
  1. run方法:实现依赖的逻辑,或者说是实现微服务之间的调用;
  2. getFallBack方法:实现服务降级处理逻辑,只做熔断处理的则可不实现;
使用时,可参考如下方式:
  1. public class TestCommand extends HystrixCommand<String> {
  2. protected TestCommand(HystrixCommandGroupKey group) {
  3. super(group);
  4. }
  5. @Override
  6. protected String run() throws Exception {
  7. //这里需要做实际调用逻辑
  8. return "Hello";
  9. }
  10. public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
  11. TestCommand command = new TestCommand(HystrixCommandGroupKey.Factory.asKey("TestGroup"));
  12. //1.这个是同步调用
  13. command.execute();
  14. //2.这个是异步调用
  15. command.queue().get(500, TimeUnit.MILLISECONDS);
  16. //3.异步回调
  17. command.observe().subscribe(new Action1<String>() {
  18. public void call(String arg0) {
  19. }
  20. });
  21. }
  22. }
细心的同学肯定发现Command机制里大量使用了Observable相关的API,这个是什么呢?原来其隶属于RxJava,这个框架就不多介绍了 --- 响应式开发,也是Netflix的作品之一,具体大家可参考这系列博客,我觉得作者写的很通俗:http://blog.csdn.net/lzyzsd/article/details/41833541/
接着呢,大家一定会问,那之前说的熔断阈值设置等,都在哪块做的呢?再来看看另一块核心代码:
  1. public abstract class HystrixPropertiesStrategy {
  2. public HystrixCommandProperties getCommandProperties(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {
  3. return new HystrixPropertiesCommandDefault(commandKey, builder);
  4. }
  5. ......
  6. }
这个类作为策略类,返回相关的属性配置,大家可重新实现。而在具体的策略中,主要包括以下几种策略属性配置:
  1. circuitBreakerEnabled:是否允许熔断,默认允许;
  2. circuitBreakerRequestVolumeThreshold:熔断器是否开启的阀值,也就是说单位时间超过了阀值请求数,熔断器才开;
  3. circuitBreakerSleepWindowInMilliseconds:熔断器默认工作时间,超过此时间会进入半开状态,即允许流量做尝试;
  4. circuitBreakerErrorThresholdPercentage:错误比例触发熔断;
  5. ......
属性很多,这里就不一一说明了,大家可参考HystrixCommandProperties类里的详细定义。还有一点要着重说明的,在熔断器的设计里,隔离采用了线程的方式(据说还有信号的方式,这两个区别我还没搞太明白),处理依赖并发和阻塞扩展,示意图如下:

如上图,好处也很明显,对于每个依赖都有独立可控的线程池,当然高并发时,CPU切换较多,有一定的影响。
啰嗦了一堆,最后总结一下,我认为服务熔断和服务降级两者是有区别的,同时通过对Hystrix的简单学习,了解了其实现机制,会逐步引入到我们的产品研发中。当然还有好多概念:服务限流、分流,请求与依赖分离等,后面有时间一一与大家分享。 

服务容错保护断路器Hystrix之六:服务熔断和服务降级的更多相关文章

  1. 服务容错保护断路器Hystrix之六:缓存功能的使用

    高并发环境下如果能处理好缓存就可以有效的减小服务器的压力,Java中有许多非常好用的缓存工具,比如Redis.EHCache等,当然在Spring Cloud的Hystrix中也提供了请求缓存的功能, ...

  2. 服务容错保护断路器Hystrix之七:做到自动降级

    从<高可用服务设计之二:Rate limiting 限流与降级>中的“自动降级”中,我们这边将系统遇到“危险”时采取的整套应急方案和措施统一称为降级或服务降级.想要帮助服务做到自动降级,需 ...

  3. 服务容错保护断路器Hystrix之五:配置

    接着<服务容错保护断路器Hystrix之二:Hystrix工作流程解析>中的<2.8.关于配置>再列举重要的配置如下 一.hystrix在生产中的建议 1.保持timeout的 ...

  4. 服务容错保护断路器Hystrix之三:断路器监控(Hystrix Dashboard)-单体监控

    turbine:英 [ˈtɜ:baɪn] 美 [ˈtɜ:rbaɪn] n.汽轮机;涡轮机;透平机 一.Hystrix Dashboard简介 在微服务架构中为了保证程序的可用性,防止程序出错导致网络阻 ...

  5. 服务容错保护断路器Hystrix之二:Hystrix工作流程解析

    一.总运行流程 当你发出请求后,hystrix是这么运行的 红圈 :Hystrix 命令执行失败,执行回退逻辑.也就是大家经常在文章中看到的“服务降级”. 绿圈 :四种情况会触发失败回退逻辑( fal ...

  6. 服务容错保护断路器Hystrix之一:入门示例介绍(springcloud引入Hystrix的两种方式)

    限流知识<高可用服务设计之二:Rate limiting 限流与降级> 在微服务架构中,我们将系统拆分成了一个个的服务单元,各单元间通过服务注册与订阅的方式互相依赖.由于每个单元都在不同的 ...

  7. 服务容错保护断路器Hystrix之八:Hystrix资源隔离策略

    在一个基于微服务的应用程序中,您通常需要调用多个微服务完成一个特定任务.不使用舱壁模式,这些调用默认是使用相同的线程来执行调用的,这些线程Java容器为处理所有请求预留的.在高服务器请求的情况下,一个 ...

  8. 服务容错保护断路器Hystrix之四:断路器监控(Hystrix Dashboard)-turbine集群监控

    turbine 英[ˈtɜ:baɪn] n. 汽轮机; 涡轮机; 透平机; OK,上文我们看了一个监控单体应用的例子,在实际应用中,我们要监控的应用往往是一个集群,这个时候我们就得采取Turbine集 ...

  9. Spring Cloud(四):服务容错保护 Hystrix【Finchley 版】

    Spring Cloud(四):服务容错保护 Hystrix[Finchley 版]  发表于 2018-04-15 |  更新于 2018-05-07 |  分布式系统中经常会出现某个基础服务不可用 ...

随机推荐

  1. Prime Test(POJ 1811)

    素数判定的模板题,运用米勒-罗宾素数判定,然后用Pollard_Rho法求出质因数.使用相应的模板即可,不过注意存储质因子的数组需要使用vector,并且使用long long类型存储,不然存储不下, ...

  2. PTA——输出各位数字

    PTA 7-37 输出整数各位数字 方法1: #include <stdio.h> #define N 10000 int main(){ long n, temp; ; scanf(&q ...

  3. django CBV和FBV写法总结

    一.FBV function base views 平常我们的写法,一个URL对应一个视图函数 二.CBV 1.url 配置 path('test/',views.CBVTest.as_views() ...

  4. UV纹理+修改器:VertexWeightEdit+修改器:Mask遮罩

    UV纹理+修改器: VertexWeightEdit+修改器: Mask遮罩 基本流程, 如下图,准备地图一份, 黑白色即可. 纹理使用颜色绘制权重. 白色为1, 黑色为0. 新增球体, 细分多次, ...

  5. da shu mo ban

    #include<bits/stdc++.h> using namespace std; ;/*精度位数,自行调整*/ //1.如果需要控制输出位数的话,在str()里面把len调成需要的 ...

  6. 【BZOJ1305】【CQOI2009】 dance跳舞

    看menci的博客点出二分的思路然后做出来,menci太强辣 原题: 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲. ...

  7. linux网络编程概念(一)

    AF表示地址族(address family) PF表示协议族(protocol family) domain参数 AF_UNIX 内核中通信 sockaddr_un AF_INET 通过ipv4 s ...

  8. Benthos metrcis 说明

    Benthos 按照input, pipeline ,buffer,conditions,ouput 这个几个大类,为我们提供了 方便的分析metrics,支持json 格式同时可以暴露为 stats ...

  9. auto sudo password in shell

    here is the example how to implement the auto password in shell script. Echo yourpasswordhere | sudo ...

  10. CodeBlocks中去掉下划线的方法

    [问题] 如上图所示,某些字符下面会出现红色下划线,看着挺难受后的,决定想办法去掉. 这是拼写检查插件在作怪,把这个插件屏蔽掉就OK了. [步骤一]点击[插件]下的[管理插件]按钮 [步骤二]点击[管 ...