熔断器Hystrix

在微服务框架 SpringCloud 中,可以用 RestTemplate 配合 RibbonFeign实现 服务与服务 之间的 相互调用

为了保证服务的 高可用单个服务 通常会采用 集群部署。由于 网络原因,服务并不能保证 100%可用性,如果 单个服务 出现问题,调用这个服务就会出现 线程阻塞,此时若有 大量的请求涌入, Servlet 容器的 线程资源 会被耗尽,导致 服务瘫痪

服务与服务之间具有 依赖性,故障会传播,导致整个微服务系统发生 雪崩

正文

Netflix 开源了 Hystrix 组件,实现了 熔断器模式SpringCloud 对这个组件进行了整合。在微服务架构中,一个请求需要调用 多个服务 是非常常见的,如下图所示:

下层 的服务如果出现故障,会导致 故障级联效应。当对特定的服务的调用的 失败次数 达到一个 阀值Hystrix520 次),断路器 将会被打开。

断路器 打开后 底层服务 将会隔断,可用避免 故障级联 问题,上层服务 调用 fallback 方法直接返回一个 固定值

在Ribbon上使用熔断器

pom.xml 文件中引入 hystrix起步依赖 spring-cloud-starter-hystrix

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

在应用的启动类上使用 @EnableHystrix 开启 hystrix 的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@EnableHystrix
@EnableDiscoveryClient
@SpringBootApplication
public class ServiceRibbonApplication {

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


@Bean
@LoadBalanced
public RestTemplate restTemplate () {
return new RestTemplate ();
}
}

使用注解 @HystrixCommand 标记调用失败时需要熔断的方法, fallbackMethod属性指定 降级方法方法名fallback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Service
public class HelloService {

@Autowired
private RestTemplate restTemplate;


@HystrixCommand(fallbackMethod = "fallback")
public String requestForHiService(String name){
return restTemplate.getForObject("http://SERVICE-HI/hi?name=" + name, String.class);
}


public String fallback(String name){
return "Fallback method invoked, name is " + name;

}
}

在Feign上使用熔断器

Feign 是自带 断路器 的,不过需要在 配置文件 中开启 hystrix 的配置。

1
2
3
feign:
hystrix:
enabled: true

Hystrix 支持 降级回退 操作,当 发生熔断出现错误 时,调用会执行 默认代码路径

1
2
3
4
5
@FeignClient(value = "service-hi", fallback = HelloServiceFallback.class)
public interface HelloService {
@RequestMapping(value = "/hi", method = RequestMethod.GET)
String sayHi(@RequestParam(value = "name") String name);
}

通过设置 fallback 属性为实现 降级回退,来启用 @FeignClient失败降级

1
2
3
4
5
6
7
8
@Service
public class HelloServiceFallback implements HelloService {

@Override
public String sayHi (String name) {
return "Fallback method invoked, name is " + name;
}
}

如果需要获取导致 回退触发 的原因,可以指定 @FeignClient 注解内部的 fallbackFactory 属性, fallbackFactory 属性和 fallback 属性不能一起使用。

1
2
3
4
5
@FeignClient(value = "service-hi", fallbackFactory = HelloServiceFallbackFactory.class)
public interface HelloService {
@RequestMapping(value = "/hi",method = RequestMethod.GET)
String sayHi(@RequestParam(value = "name") String name);
}

然后提供一个 FallbackFactory实现类,实现类指定 泛型参数HelloService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Component
public class HelloServiceFallbackFactory implements FallbackFactory<HelloService> {

@Override
public HelloService create(Throwable throwable) {
return new HelloService() {
@Override
public String sayHi(String name) {
return "Fallback method invoked, name is "
+ name +", message is "+ throwable.getMessage();

}

};

}
}