SpringCloud模拟微服务5-服务熔断Hystrix
一.Hystrix简介
二.雪崩问题
微服务中,拿上几篇文章 的项目举例,如果一个user-service宕机了,那么会引擎consumer-demo也不能使用,就是雪崩
服务器支持的线程和并发数有限,请求一直阻塞,会导致服务器资源耗尽,从而导致所以其他服务都不可用,形成雪崩效应。
这就好比,一个汽车生产线,生产不同的汽车,需要使用不同的零件,如果某个零件因为种种原因无法使用,那么就会造成整台汽车无法装配,陷入等待零件的状态,直到零件到位,才能继续安装。此时如果有很多个车型都需要这个零件,那么整个工厂都陷入等待。
解决雪崩问题的方式:
- 线程隔离
- 服务熔断
三.线程隔离,服务降级
使得tomcat线程资源只是有限的被占用一小部分而不占用其他的服务的线程资源
四.操作Hystrix
进行Hystrix处理的项目是服务的消费方即consumer-demo
一.添加依赖
在consumer-demo项目中引入
<!--Hystrix豪猪依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
二.添加注解
1.需要添加的@EnableCircuitBreaker注解
2.SpringCloud一键注解
正常的SpringCloud项目都会配这三个注解
@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
因此我们有了一个注解替代全部的方式@SpringCloudApplication注解
通过Ctrl+单击查看SpringCloud注解
三.编写失败处理
1.修改consumer-demo下的web服务controller
添加失败容错指令注解@HystrixCommand
意思是要开启线程隔离和降级处理
2.失败处理方法
该方法必须传递的方法跟成功方法一样,返回值跟成功方法一样,因此原来的成功方法被迫改成String格式来传递User信息,但不影响结果,因为前端也只是接收一个json格式数据。
@RestController
@RequestMapping("consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("{id}")
@HystrixCommand(fallbackMethod = "queryByIdFallback")
public String queryById(@PathVariable("id") Long id){
String url = "http://user-service/user/"+id;
String user = restTemplate.getForObject(url,String.class);
return user;
}
public String queryByIdFallback(Long id){
return "不好意思,服务器太拥挤";
}
}
3.模拟超时检测结果
在user-service上添加休眠sleep()并try-catch
修改user-service的service层中的UserService.class,添加红框下代码。
4.显示结果
启动eureka-server,user-service,consumer-demo
输入:localhost:8088/consumer/1
页面显示
5.解释一下
页面按F12,再次刷新一下页面(重新提交一次请求的意思)
项目反应时间27ms,但是请求睡眠了2秒,所以超时了,因此触发了服务的降级。
6.处理问题
1.小问题1
上述写法有一个小问题,如果我的controller方法特别多的话,那n个成功方法,就对应着要写n个失败方法。
可以在service层的Userservice类上添加一个@DefaultProperties(defaultFallback = “queryByIdFallback”)注解属性(默认超时统一调用queryByIdFallback这个方法)
@RestController
@RequestMapping("consumer")
//修改1:添加@DefaultProperties注解,配置成一个默认通用方法,只要超时就只调用里面的属性
@DefaultProperties(defaultFallback = "queryByIdFallback")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("{id}")
//修改2:这里的参数可以去掉了,@HystrixCommand注解保留
@HystrixCommand
public String queryById(@PathVariable("id") Long id){
String url = "http://user-service/user/"+id;
String user = restTemplate.getForObject(url,String.class);
return user;
}
//修改3:这个方法的传递参数可以去掉了
public String queryByIdFallback(){
return "不好意思,服务器太拥挤";
}
}
2.小问题2
不同的业务超时的时间不用,例如短信…都需要时间多一点
手动调整某个服务超时时长
将@HystrixCommand注解修改成
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value ="3000")
})
两秒是睡眠,但是有3秒的等待时间,最后执行所花时间为2.65s,所以请求仍然成功
3.小问题3
如果需要全局配置
并且将consumer-demo的controller@Hystrix注解注释掉
4.小问题4
不写默认的default,而是只针对某个服务设置服务超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
user-service: #只针对user-service服务设置最大超时时间
execution:
isolation:
thread:
timeoutInMilliseconds: 3000