由于后起之秀 Sentinel 的诞生,不建议在新项目中再使用 Hystrix。
序言
在微服务架构中,存在着那么多的服务单元,若一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加不稳定。
为了解决这样的问题, 产生了熔断器等一系列的服务保护机制。
在分布式架构中, 断路器模式的作用也是类似的,当某个服务单元发生故障(类似电器发生短路) 之后, 通过熔断器的故障监控(类似熔断保险丝), 向调用方返回一个错误响应, 而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
Hystrix 就是一种熔断器,具备服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能.。
Hystrix:服务容错保护
快速入门
改造原有 demo,在consumer
加入 Hystrix 熔断器。
① 添加依赖
在consumer
的pom.xml
文件加入依赖:1
2
3
4<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
② 添加注解
在consumer
的启动类上加入@SpringCloudApplication
注解:1
2
3
4
5
6
7
8
9
10
11
12
public class ConsumerApplication {
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
}
该注解相当于以下 3 个注解的集合体 :
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
之后在控制类上加入 Hystrix 相关的注解@HystrixCommand
,如对consumer
模块的ConsumerController
类修改如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"consumer") (
public class ConsumerController {
private RestTemplate restTemplate;
"{id}") (
"queryByIdFallback") (fallbackMethod =
public String queryById(@PathVariable("id") Integer id) {
String url = "http://user-service/user/" + id;
return restTemplate.getForObject(url, String.class);
}
public String queryByIdFallback(Integer id) {
return "不好意思,服务器太拥挤了,请稍后再试";
}
}
这代表当调用queryById
方法一定时间(默认 1 秒)未执行时,Hystric 将转而执行指定的queryByIdFallback
方法以避免故障的蔓延。
疑问
问
:我们只对queryById
方法使用了 Hystric 熔断器,但具体场景可能不止一个方法需要这么做,如何解决这个问题呢?答
:我们可以直接在controller
类上使用@DefaultProperties
注解并指定方法,之后在相关方法上使用@HystrixCommand
注解,熔断超时都会转发到那个方法,改造的代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"consumer") (
"defaultFallback") (defaultFallback =
public class ConsumerController {
private RestTemplate restTemplate;
"{id}") (
public String queryById(@PathVariable("id") Integer id) {
String url = "http://user-service/user/" + id;
return restTemplate.getForObject(url, String.class);
}
public String defaultFallback() {
return "不好意思,服务器太拥挤了,请稍后再试";
}
}
问
:前面我们的查询方法使用 Hystrix 熔断器后默认的超时时间为 1 秒,但在不同的场景中可能需要设置不同的时间,该怎么修改呢?答
:可以对具体的方法上的@HystrixCommand
设置超时时间,示例如下:1
2
3
4
5
6
7
8"{id}") (
(commandProperties = {
"execution.isolation.thread.timeoutInMilliseconds",value = "2000") (name =
})
public String queryById(@PathVariable("id") Integer id) {
String url = "http://user-service/user/" + id;
return restTemplate.getForObject(url, String.class);
}
③ 修改 user-service 模块并测试
首先我们修改user-service
模块的controller
层的UserController
类来模拟线程故障:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"/user") (
public class UserController {
private UserServiceImpl userService;
"/{id}") (
public User queryById(@PathVariable("id") Integer id) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return userService.queryById(id);
}
}
启动 3 个模块进行测试,访问http://localhost:8080/consumer/1
的结果如下:1
不好意思,服务器太拥挤了,请稍后再试
④ 修改配置文件
问
:前面 Hystrix 熔断器可以对具体的方法设置熔断时间,那有没有配置能设置全局超时参数呢?答
:当然有,在application.yml
文件添加如下配置即可修改相关模块 Hystrix 熔断器的全局默认时间为 2 秒了:1
2
3
4
5
6
7hystrix:
commond:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000