Spring-Boot

系统的保险丝-断路器

2018-12-24  本文已影响30人  大哥你先走

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

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

1. 错误,只能接受

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

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


断路器状态转移.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

    @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);
    }
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
@SpringBootApplication
@EnableCircuitBreaker
public class CircuitBreakersClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(CircuitBreakersClientApplication.class, args);
    }

}
    @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

 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

上一篇下一篇

猜你喜欢

热点阅读