美文网首页Spring-Boot
系统的保险丝-断路器

系统的保险丝-断路器

作者: 大哥你先走 | 来源:发表于2018-12-24 00:05 被阅读30次

    目前微服务架构的优势(低耦合、可重用、业务敏捷、适合云模式)已经得到广泛的认可,与此同时,微服务架构使得系统的整体架构变得十分脆弱,因为一个客户端调用需要多个微服务配合完成。微服务通过网络上的远程调用取代了单体架构中的内存调用,在所有微服务已经启动并正常运行时能很好的工作。但是,当一个或多个微服务可不用或高延迟时,可能触发系统级联故障,甚至导致整个系统雪崩。客户端的重试策略,只能让服务端变的更糟糕,甚至导致服务端加快宕机。

    断路器类似每个家庭里安装的空气开关,当家里所有电器的功率超过限定功率时,为了保护家用电器,空气开关会自动打开切断家庭的所有电源。当我们关闭不必要的电器后,可手动关闭空气开关,家里的供电又恢复正常,而且没有电器因为其它大功率的电器而受损。在系统设计领域也一样,断路器模式可以帮助解决多个系统之间的级联故障(大功率电器影响甚至破坏其他电器),断路器模式可以帮助您构建容错和弹性系统,当关键服务不可用或具有高延迟时,系统依然可以正常运行。

    1. 错误,只能接受

    所有的服务在某个时间点都会失败,这一点我们只能接受。断路器允许系统优雅地处理这些故障。 断路器概念很简单。 它用跟踪故障的监视器包装一个函数。 断路器可以当作一个有限状态机,断路器有3种不同的状态:关闭,打开和半打开:

    • Closed(关闭) – 在一切正常的情况下,断路器处于关闭状态,所有请求都会传递到后端服务。当失败次数超过断路器“跳闸”阀值时,断路器由关闭状态切换到打开状态。
    • Open(打开) – 断路器直接返回错误(不调用任何函数)。
    • Half-Open(半打开) – 经过一个超时周期后,断路器切换到半打开状态,并检查错误是否仍然存在。在半打开状态模式下,如果一个调用失败,断路器重新切换到打开状态;如果成功,断路器切换到关闭状态。

    短路器的状态转移图如下:


    断路器状态转移.png

    1. 1断路器-关闭状态

    当断路器处于关闭状态,所有的调用都会到达后端服务,后端服务可以正常的对请求作出响应。
    关闭状态下,请求的UML序列图如下:


    关闭状态.png

    1.2 断路器-打开状态

    假如,后端的微服务对请求的处理正在变慢,断路器会收到所有对该微服务的请求都超时。一旦,请求超时的次数超过设置的阀值,就会触发断路器有关闭状态切换到打开状态。在打开状态,所有对该微服务的请求,断路器都会直接返回错误,而不再将请求转发到微服务,这允许微服务从高负载状态慢慢恢复到正常。
    打开状态下,请求的UML序列图如下:


    打开状态.png

    1.3 断路器-半打开状态

    断路器使用称为HALF-OPEN状态的监控和反馈机制来了解微服务是否以已经恢复。 这种机制定期对商微服务进行测试,以检查它是否已经恢复。 如果对微服务的调用超时,则断路器保持在打开状态。 如果调用返回成功,则切换到关闭状态。断路器在HALF-OPEN状态期间所有对微服务的外部调用都会收到一个错误。
    半打开状态下,请求的UML序列图如下:


    半打开.png

    2. 实战

    2.1 实战场景

    有两个服务,为了简化描述称为server和client。server提供REST接口供客户端查询天气信息,client通过RestTemplate调用server的接口,并最终将天气信息呈现给用户。

    2.2 SpringBoot + hystrix

    • 服务端
      服务端提供REST接口查询天气信息,示意代码如下:
        @RequestMapping(value = "/api/v1.0/weather", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
        public ResponseEntity<WeatherInfo> getWeatherInfo() throws Exception {
            WeatherInfo weatherInfo = new WeatherInfo();
            weatherInfo.setType("sunshine");
            weatherInfo.setHumidity(random.nextDouble());
            weatherInfo.setTemperature(random.nextDouble());
            return new ResponseEntity<>(weatherInfo, HttpStatus.OK);
        }
    
    • 客户端
        1. 在SpringBoot中使用hystrix,需要引入对应的依赖,maven依赖如下:
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
                <version>2.0.1.RELEASE</version>
            </dependency>
    
      1. 通过注解@EnableCircuitBreaker打开断路器功能:
    @SpringBootApplication
    @EnableCircuitBreaker
    public class CircuitBreakersClientApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(CircuitBreakersClientApplication.class, args);
        }
    
    }
    
      1. 通过注解@HystrixCommand指定断路器打开时调用的方法:
        @HystrixCommand(fallbackMethod = "defaultInfo")
        public WeatherInfo getWeatherInfo() {
            log.info("enter getWeatherInfo method");
            ResponseEntity<WeatherInfo> response = template.getForEntity(URI, WeatherInfo.class);
            return response.getBody();
        }
    

    2.3 SpringBoot + resilience4j

    • 服务端
      服务端实现和SpringBoot+hystrix一致

    • 客户端

     public WeatherInfo queryWeatherInfo() {
            try {
                return circuitBreaker.executeCallable(new Callable<WeatherInfo>() {
                    @Override
                    public WeatherInfo call() throws Exception {
                        ResponseEntity<WeatherInfo> response = template.getForEntity(URI, WeatherInfo.class);
                        return response.getBody();
                    }
                });
            } catch (Exception e) {
                log.info("exception = {}", e.toString());
            }
            return defaultInfo();
        }
    

    完整代码可从Github获取。

    3 参考文献

    [1] resilience4j
    [2] SpringCloud

    相关文章

      网友评论

        本文标题:系统的保险丝-断路器

        本文链接:https://www.haomeiwen.com/subject/egigkqtx.html