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.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 应该里面的错误处理方法替换了。
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 一样的效果。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于