跳闸了啊! 服务容灾:熔断器简介

雪崩效应

现现在SOA、微服务风愈演愈烈,愈来愈多的业务和资源被以服务的形式包装和发布,服务间又可能会依赖其余各类服务。由此而来不可避免的会产生不少问题。html

好比一个服务,其依赖了另外30个服务。假设每一个服务的可用率都有三个9(99.9%),那么咱们计算一下:前端

99.99%^30 = 99.7%nginx

现实很残酷,这个服务的实际可用性只能是99.7%,也就是说每月这个服务都要好宕机8000+秒~~~git


正经常使用户请求时,服务内部依次请求A\P\H\I服务,兵返回响应结果。github


很是不幸,咱们的I服务出了某些问题,此时咱们的用户请求就被堵塞在I服务处。spring


更加悲剧的是,后续愈来愈多的请求都被堵塞在I服务处,而这些被堵塞的请求会占用线程、IO、网络等系统资源,随着资源被占用的愈来愈多,原本不存在的性能问题也会随之而来,形成系统中的其余服务出现问题,甚至致使系统奔溃。docker

这也就是咱们常说的雪崩效应缓存


服务容灾

为了不出现服务的雪崩,咱们须要对服务作容灾处理。服务器

常规的服务容灾处理思路有:网络

  • 资源隔离
  • 超时设定
  • 服务降级
  • 服务限流

其中每种思路又能够有不一样的解决方案。

好比资源隔离能够经过将不一样的服务发布在独立的docker容器或服务器中,这样即便一个服务出现问题,也不会殃及池鱼。

服务降级和服务限流能够经过前端nginx+lua来实现,当服务处理延迟或宕机时,nginx能够直接返回固定的降级/失败响应,已快速跳过问题服务。


Hystrix

Hystrix,是Netflix的一个开源熔断器,经过Hystrix,咱们能够很方便的实现资源隔离、限流、超时设计、服务降级等服务容灾措施,而且还提供了强大的监控,能够查看各个熔断器的容许状况。

经过上图,能够看出,Hystrix提供了一个HystrixCommand用来包装调用请求。HystrixCommand的执行流程大概以下:
1.首先检查缓存中是否有结果。若是有则直接返回缓存结果。
2.判断断路器是否开启,若是断路器闭合,执行降级业务逻辑并返回降级结果。
3.判断信号量/线程池资源是否饱和,如饱和则执行降级业务逻辑并返回降级结果。
4.调用实际服务,如发生异常,执行降级业务逻辑并返回降级结果,并调整断路器阈值。
5.判断实际业务是否超时,超时则返回超时响应结果,并调整断路器阈值。

了解了流程,来看下如何使用Hystrix。首先咱们须要定义一个命令类来包装咱们的业务调用:

//继承HystrixCommand
public class CommandHelloFailure extends HystrixCommand<String> {

    private final String name;

    public CommandHelloFailure(String name) {
        //设置分组key,分组key能够用在报表、监控中,默认的线程池隔离也基于分组key
         super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
            //指定命令key,可
            .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
            //指定线程池key,取代默认的分组key
            .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
        /*
        //线程池隔离模式,不写默认是线程池隔离模式
        HystrixCommandProperties.Setter()
           .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)
        //信号量隔离模式
        HystrixCommandProperties.Setter()
           .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
        //超时时间,默认1秒
        HystrixCommandProperties.Setter()
           .withExecutionTimeoutInMilliseconds(int value)  
        //信号量模式下,最大并发请求限流,默认值10
        HystrixCommandProperties.Setter()
           .withFallbackIsolationSemaphoreMaxConcurrentRequests(int value)  
        //熔断器阈值,默认20
        HystrixCommandProperties.Setter()
            .withCircuitBreakerRequestVolumeThreshold(int value)
        //熔断器关闭时间,默认5秒
        HystrixCommandProperties.Setter()
            .withCircuitBreakerSleepWindowInMilliseconds(int value)
        */
        this.name = name;
    }

    @Override
    //执行实际服务,这里模拟所有返回异常
    protected String run() {
        throw new RuntimeException("this command always fails");
    }

    @Override
    //执行降级业务
    protected String getFallback() {
        return "Hello Failure " + name + "!";
    }

    @Override
    //从缓存中获取
    protected String getCacheKey() {
        ...
    }
}

使用这个命令类也很是简单:

//同步执行
String s = new CommandHelloWorld("Bob").execute();
//异步执行
Future<String> s = new CommandHelloWorld("Bob").queue();
//响应式
Observable<String> s = new CommandHelloWorld("Bob").observe();

经过Hystrix提供的监控界面,咱们能够观察到各个熔断器的执行状况:

更多说明和例子能够查看Hystrix的wiki


Hystrix和Spring boot

想在spring boot中使用Hystrix就更加简单了,只须要引入spring-cloud-starter-hystrix,

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>

而后添加注解使用Hystrix
@EnableCircuitBreaker
@EnableHystrixDashboard

最后在须要使用熔断器的地方标记注解便可。

@HystrixCommand(groupKey = "xxx", fallbackMethod = "yyy")
public String doSomething()

遥想2015年9月7日,上交所、深交所、中金所宣布,拟在保留现有个股涨跌幅制度前提下,引入指数熔断机制。随后A股联系两天下跌熔断,提早收盘。其中这里的熔断机制和咱们今天讨论的熔断器思路一致,可是反而致使了A股暴跌,这也说明了咱们仍是得从根源产出高可用的服务,而不是依赖某些外部措施帮助咱们提升可用性。同时说明了A股比咱写的垃圾服务更加不可靠,仍是安心当个码农吧。

最后,就问各位童鞋,敢不敢点个赞~~~~

参考资料: https://github.com/Netflix/Hystrix http://www.cnblogs.com/jesse2013/p/things-architect-must-know.html

相关文章
相关标签/搜索