熔断器,旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。
比如某个小弟故障了,你调用它半天没有响应,你却不知道,一直在等这个响应,这时别的小弟也在调用你的服务,那么当请求多了,就会发生严重的阻塞。这个时候Hystrix就派上用场了,Hystrix发现某个小弟不在状态不稳定立马让它下线,让其它小弟来顶上来,或者给你说不用等了这个小弟今天肯定不行,该干嘛赶紧干嘛去别在这排队了。
借用一下上篇文章:https://blog.youkuaiyun.com/hjy132/article/details/84783413 ,服务注册中心、服务提供者以及服务消费者的程序。
- 启动注册中心eureka服务cloud_eureka_server
- 启动两个服务cloud_service,端口分别为9881和9882
- 启动cloud_web工程
在没有加入熔断器之前,关闭9881的服务,发生GET请求http://localhost:9884/cloudweb/helloFang,页面显示如下信息:
下面开始引入Spring Cloud Hystrix
(1)在cloud_web工程pom.xml中引入Hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
(2)在启动主类中使用注解@EnableCircuitBreaker开启断路器功能
@EnableDiscoveryClient
@EnableCircuitBreaker
@SpringBootApplication
public class CloudWebApplication {
/*Spring提供的用于访问Rest服务的客户端*/
@Bean
@LoadBalanced //开启客户端负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(CloudWebApplication.class, args);
}
}
(3)改造服务消费方式,新增CloudWebService类,注入RestTemplate实例,然后将CloudWebController中对RestTemplate的使用迁移到helloFang函数中,并增加@HystrixCommand注解来指定回调方法
@Service
public class CloudWebService {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand( fallbackMethod = "helloFallback")
public String helloFang(){
ResponseEntity<String> p=restTemplate.getForEntity("http://cloudservice/hello?para={1}",String.class,"hjy");
return p.getBody();
}
public String helloFallback(){
return "error";
}
}
(4)修改CloudWebController类
@RestController
public class CloudWebController {
@Autowired
private CloudWebService cloudWebService;
@RequestMapping(value = "/helloFang",method = RequestMethod.GET)
public String helloFang(){
return cloudWebService.helloFang();
}
}
(5)测试
重启刚才关掉9881端口的服务cloud_service,访问http://localhost:9884/cloudweb/helloFang可以轮询两个服务cloudservice,此时关闭9881端口的服务,当轮询到9881端口的服务时,输出以下内容:(不再是之前的错误了,Hystrix服务回调生效)
(6)阻塞测试
下面模拟一下服务阻塞(长时间未响应)的情况,我们对cloud_service的/hello接口做一些修改
@RestController
public class HelloController {
@Autowired
private DiscoveryClient client;
@RequestMapping("hello")String hello(HttpServletRequest request) throws Exception {
String s=request.getParameter("para");
ServiceInstance instance=client.getLocalServiceInstance();
//让处理线程等待几秒钟
int a=new Random().nextInt(2000);
System.out.println("睡眠时间:"+a);
Thread.sleep(a);
return "host:"+instance.getHost()+" ServiceId:"+instance.getServiceId()+
" port:"+instance.getPort()+" 参数为:"+s+" 睡眠时间:"+a;
}
}
由于Hystrix默认超时时间为1000ms,所以这里以一定概率发生超时来触发断路器。为了更精准观察断路器触发,在消费者调用函数中做时间记录:
@Service
public class CloudWebService {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand( fallbackMethod = "helloFallback")
public String helloFang(){
long start=System.currentTimeMillis();
ResponseEntity<String> p=restTemplate.getForEntity("http://cloudservice/hello?para={1}",String.class,"hjy");
long end=System.currentTimeMillis();
System.out.println("消耗时间:"+(end-start));
return p.getBody()+" 消耗时间:"+(end-start);
}
public String helloFallback(){
return "请求超时";
}
}
重新启动cloud_service和cloud_web实例,连续访问http://localhost:9884/cloudweb/helloFang几次,发现消耗时间大于1000ms时,就会返回请求超时。
在application.yml中可修改Hystrix的超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 8000