Spring Cloud 入门 (七): 熔断机制 -- 断路器

本贴最后更新于 2000 天前,其中的信息可能已经时移世改

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

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

图中的服务 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.cloudgroupId>
    <artifactId>spring-cloud-starter-hystrixartifactId>
<dependency>

2. 在 Ribbon 应用中使用断路器

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

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ServiceRibbonApplication {

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

2). 用 @HystrixCommand 注解标注访问服务的方法

@Service
public class HelloService {
    @Autowired RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "serviceFailure")
    public String getHelloContent() {
        return restTemplate.getForObject("http://SERVICE-HELLOWORLD/",String.class);
    }

    public String serviceFailure() {
        return "hello world service is not available !";
    }
}

@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 应该里面的错误处理方法替换了。

imagepng imagepng

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

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

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

@FeignClient(name = "SERVICE-HELLOWORLD", fallback = HelloWorldServiceFailure.class) 
public interface HelloWorldService { 
  @RequestMapping(value = "/", method = RequestMethod.GET) 
  public String sayHello();  
}

3). 创建 HelloWorldServiceFailure 类, 必须实现被 @FeignClient 修饰的 HelloWorldService 接口。注意添加 @Component 或者 @Service 注解,在 Spring 容器中生成一个 Bean

@Component
public class HelloWorldServiceFailure implements HelloWorldService {
    @Override
    public String sayHello() {
        System.out.println("hello world service is not available !");
        return "hello world service is not available !";
    }
}

4). 要在 Feign 中使用断路器, 必须在 application.yml 中添加如下配置:

feign:
   hystrix:
     enabled: true

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

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    941 引用 • 1458 回帖 • 151 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...