Spring Cloud 熔断机制 -- 断路器

Spring Cloud 入门教程(七): 熔断机制 -- 断路器
对断路器模式不太清楚的话,可以参看另一篇博文:断路器(Curcuit Breaker)模式,下面直接介绍Spring Cloud的断路器如何使用。

SpringCloud Netflix实现了断路器库的名字叫Hystrix. 在微服务架构下,通常会有多个层次的服务调用. 下面是微服架构下, 浏览器端通过API访问后台微服务的一个示意图:



 

一个微服务的超时失败可能导致瀑布式连锁反映,下图中,Hystrix通过自主反馈实现的断路器, 防止了这种情况发生。



 图中的服务B因为某些原因失败,变得不可用,所有对服务B的调用都会超时。当对B的调用失败达到一个特定的阀值(5秒之内发生20次失败是Hystrix定义的缺省值), 链路就会被处于open状态, 之后所有所有对服务B的调用都不会被执行, 取而代之的是由断路器提供的一个表示链路open的Fallback消息.  Hystrix提供了相应机制,可以让开发者定义这个Fallbak消息.

open的链路阻断了瀑布式错误, 可以让被淹没或者错误的服务有时间进行修复。这个fallback可以是另外一个Hystrix保护的调用, 静态数据,或者合法的空值. Fallbacks可以组成链式结构,所以,最底层调用其它业务服务的第一个Fallback返回静态数据.

下面,进入正题,在之前的两HELLO WORLD服务集群中加入断路器, 防止其中一个Hello world挂掉后, 导致系统发生连锁超时失败。

1. 在maven工程(前面章节中介绍的Ribbon或者Feign工程)的pom.xml中添加hystrix库支持断路器

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
2. 在Ribbon应用中使用断路器

1). 在Spring Boot启动类上添加@EnableCircuitBreaker注解

复制代码
1 @SpringBootApplication
2 @EnableDiscoveryClient
3 @EnableCircuitBreaker
4 public class ServiceRibbonApplication {
5 
6     public static void main(String[] args) {
7         SpringApplication.run(ServiceRibbonApplication.class, args);
8     }
。。。 。。。
复制代码
2). 用@HystrixCommand注解标注访问服务的方法

复制代码
 1 @Service
 2 public class HelloService {
 3     @Autowired RestTemplate restTemplate;
 4 
 5     @HystrixCommand(fallbackMethod = "serviceFailure")
 6     public String getHelloContent() {
 7         return restTemplate.getForObject("http://SERVICE-HELLOWORLD/",String.class);
 8     }
 9 
10     public String serviceFailure() {
11         return "hello world service is not available !";
12     }
13 }
复制代码
@HystrixCommand注解定义了一个断路器,它封装了getHelloContant()方法, 当它访问的SERVICE-HELLOWORLD失败达到阀值后,将不会再调用SERVICE-HELLOWORLD, 取而代之的是返回由fallbackMethod定义的方法serviceFailure()。@HystrixCommand注解定义的fallbackMethod方法,需要特别注意的有两点:

第一,  fallbackMethod的返回值和参数类型需要和被@HystrixCommand注解的方法完全一致。否则会在运行时抛出异常。比如本例中,serviceFailure()的返回值和getHelloContant()方法的返回值都是String。

第二,  当底层服务失败后,fallbackMethod替换的不是整个被@HystrixCommand注解的方法(本例中的getHelloContant), 替换的只是通过restTemplate去访问的具体服务。可以从中的system输出看到, 即使失败,控制台输出里面依然会有“call SERVICE-HELLOWORLD”。

启动eureka服务,只启动两个Helloworld服务,然后中断其中一个(模拟其中一个微服务挂起),访问http://localhost:8901/然后刷新, 由于有负载均衡可以看到以下两个页面交替出现。可以看到第二个被挂起的服务,被定义在Ribbon应该里面的错误处理方法替换了。

         

4. 在Feign应用中使用断路器

1). Feign内部已经支持了断路器,所以不需要想Ribbon方式一样,在Spring Boot启动类上加额外注解

2). 用@FeignClient注解添加fallback类, 该类必须实现@FeignClient修饰的接口。

1 @FeignClient(name = "SERVICE-HELLOWORLD", fallback = HelloWorldServiceFailure.class)
2 public interface HelloWorldService {
3     @RequestMapping(value = "/", method = RequestMethod.GET)
4     public String sayHello();
5 }
3). 创建HelloWorldServiceFailure类, 必须实现被@FeignClient修饰的HelloWorldService接口。注意添加@Component或者@Service注解,在Spring容器中生成一个Bean

复制代码
1 @Component
2 public class HelloWorldServiceFailure implements HelloWorldService {
3     @Override
4     public String sayHello() {
5         System.out.println("hello world service is not available !");
6         return "hello world service is not available !";
7     }
8 }
复制代码
4). Spring Cloud之前的Brixton版本中,Feign是缺省是自动激活了断路器的,但最近的Dalston版本已经将缺省配置修改为禁止。

原因参见:  https://github.com/spring-cloud/spring-cloud-netflix/issues/1277, 这一点要注意。所以要在Feign中使用断路器, 必须在application.yml中添加如下配置:

feign:
   hystrix:
     enabled: true
5). 启动Feign应用, 访问http://localhost:8902/hello, 可以一看到和Ribbon一样的效果。
View Code

 

posted @ 2019-03-12 09:13  雷神约  阅读(181)  评论(0编辑  收藏  举报