阅读完需:约 6 分钟
基本介绍
Hystrix 叫做断路器/熔断器。微服务系统中,整个系统出错的概率非常高,因为在微服务系统中,涉及到的模块太多了,每一个模块出错,都有可能导致整个服务出,当所有模块都稳定运行时,整个服务才算是稳定运行。
我们希望当整个系统中,某一个模块无法正常工作时,能够通过我们提前配置的一些东西,来使得整个系统正常运行,即单个模块出问题,不影响整个系统。
中文文档:
https://www.springcloud.cc/spring-cloud-dalston.html#_circuit_breaker_hystrix_clients

我们已经成功的搭建出服务注册中心、服务提供者和服务消费者三个微服务,本文的案例我们依然在这三个案例的基础上来实现
首先我们分别启动服务注册中心,再启动两个服务提供者的实例,然后再启动一个服务消费者,这几个都启动成功之后,我们访问http://localhost:9000/ribbon-consumer
这个地址,可以看到如下效果:

此时我们关闭掉任意一个服务提供者,再去访问这个地址,会看到如下效果:


小插曲:服务提供者(生产者的接口)(接口随便!没有什么限制要求)
@RestController
public class HelloController {
@Value("${server.port}")
Integer port;
@Override
public String hello() {
String s = "hello javaboy:" + port;
System.out.println(s);
return s;
}
}
大家知道Spring Cloud中采取的默认负载均衡策略就是轮询,所以当一个服务提供者关掉之后,刷新的时候服务请求成功和请求失败是成对出现的:当服务消费者去请求那个被关掉的服务提供者的时候就会请求失败,当服务消费者去请求正常的服务提供者时就能获得期望的结果。请求失败时不能给用户展示这样一个ErrorPage,而应该是一个可控的页面,OK,我们来看看如何使用断路器来解决这个问题。

其中provider多启动几个服务,行成集群
服务消费者中加入断路器
首先我们需要在服务消费者中引入hystrix,如下:

关键点是这个:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
项目创建成功后,添加如下配置,将 Hystrix 注册到 Eureka 上:
server:
port: 9000
spring:
application:
name: hystrix
eureka:
client:
service-url:
defaultZone: http://localhost:1111/eureka
然后,在项目启动类上添加如下注解,开启断路器,同时提供一个 RestTemplate 实例:
@SpringBootApplication
@EnableCircuitBreaker
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
启动类上的注解,也可以使用 @SpringCloudApplication 代替:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
@SpringCloudApplication
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
这样,Hystrix 的配置就算完成。
接下来提供 Hystrix 的接口。
HelloService
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
/*
* 我们将发起一个远程调用,去调用 provider 中提供的 /hello 接口
* 但是这个调用可能会失败
*
* 我们在这个方法上添加 @HystrixCommand 注解,配置 fallbackMethod 属性,
* 这个属性表示该方法调用失败时的临时替代方法
*
* */
@HystrixCommand(fallbackMethod = "error")
public String hello(){
return restTemplate.getForObject("http://provider/hello",String.class);
}
/*
* 注意,这个方法名字要和 fallbackMethod 一致*
* 方法返回值也要和对应的方法一致
* */
public String error(){
return "error";
}
}
关于这个HelloService类我说如下几点:
1.RestTemplate执行网络请求的操作我们放在HelloService中来完成。
2.error方法是一个请求失败时回调的方法。
3.在hello方法上通过@HystrixCommand注解来指定请求失败时回调的方法。( 请求失败时回调 通过 @HystrixCommand注解 能一直失败回调下去)
public @interface HystrixCommand {
// HystrixCommand 命令所属的组的名称:默认注解方法类的名称
String groupKey() default "";
// HystrixCommand 命令的key值,默认值为注解方法的名称
String commandKey() default "";
// 线程池名称,默认定义为groupKey
String threadPoolKey() default "";
// 定义回退方法的名称, 此方法必须和hystrix的执行方法在相同类中
String fallbackMethod() default "";
// 配置hystrix命令的参数
HystrixProperty[] commandProperties() default {};
// 配置hystrix依赖的线程池的参数
HystrixProperty[] threadPoolProperties() default {};
// 如果hystrix方法抛出的异常包括RUNTIME_EXCEPTION,则会被封装HystrixRuntimeException异常。我们也可以通过此方法定义哪些需要忽略的异常
Class<? extends Throwable>[] ignoreExceptions() default {};
// 定义执行hystrix observable的命令的模式,类型详细见ObservableExecutionMode
ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER;
// 如果hystrix方法抛出的异常包括RUNTIME_EXCEPTION,则会被封装HystrixRuntimeException异常。此方法定义需要抛出的异常
HystrixException[] raiseHystrixExceptions() default {};
// 定义回调方法:但是defaultFallback不能传入参数,返回参数和hystrix的命令兼容
String defaultFallback() default "";
}
HelloController
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("ribbon-consumer")
public String hello(){
return helloService.hello();
}
}
此时我们就开启了断路器功能。
我们先确认服务注册中心,两个服务提供者的实例,一个服务消费者,一共四个实例都启动成功,启动成功之后,我们再关掉一个服务提供者,结果如下:
