1、介绍
项目github地址:https://github.com/Netflix/Hystrix
。
Hystix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败。
服务雪崩
在微服务架构中,服务间存在调用链是不可避免的,如下图:
①在ServiceA请求量很大的情况下,ServiceC扛不住压力挂了。
②ServiceB大量调用ServiceC的请求阻塞等待。
③ServiceB的线程资源慢慢耗尽,ServiceB也逐渐变得不可用。
④ServiceA最终也和ServiceB一样由于大量请求阻塞逐渐变得不可用。
像这样,一个服务不可用引发整条服务链路服务都不可用的事故称为服务雪崩。
要解决服务链雪崩问题,一般有两类解决方案:
- 升级硬件(此处不讨论)。
- 流控技术:资源隔离、熔断、降级、限流、缓存等。
服务熔断
当下游服务因某种原因突然变得不可用或响应过慢,上游服务为保证自己整体服务的可用性,不再继续调用目标服务,直接响应超时错误信息,快速释放资源,如果目标服务情况好转则逐渐恢复调用。
Hystix断路器工作图解:
Hystix断路器工作解析:
当调用远程服务时,断路器将监视这个调用,如调用失败次数达到一定比例,断路器将会介入并中断调用。
断路器将监视所有远程服务的调用,如对某个远程服务的调用失败次数达到一定比例(默认最少20次请求,且失败比例达到50%),那么断路器会采取快速失败操作,阻止调用失败的远程服务并直接响应失败信息,断路器由关闭变为打开状态。
一段时间(reset timeout,默认5s)后,断路器将释放一部分请求调用失败的远程服务,此时断路器变为半开状态。
若释放的远程请求成功,则断路器变为关闭状态,若远程请求任然失败,断路器重新变为打开状态。
服务降级
Ⅰ:当调用链的下游服务因某种原因响应过慢,下游服务主动停掉一些不太重要的业务,释放出服务器资源,增加响应速度。
Ⅱ:当调用链的下游服务因某种原因响应过慢或不可用,上游服务主动调用本地的一些降级逻辑,避免卡顿,迅速响应用户(默认1s无响应触发)。
资源隔离
Hystix资源隔离模式有两种:信号量隔离、线程池隔离(默认)。
如上图所示,假设ServiceA系统总共100个线程资源,当ServiceC不可用或响应过慢,刚好系统请求量较大,有可能造成100个线程资源全部阻塞在用于请求ServiceC的地方,导致请求ServiceB的HTTP也无法正常使用,整个ServiceA服务都会受到严重影响。
如上图所示,使用线程隔离后,HTTP B和HTTP C各自拥有独立的线程资源,即使发生超时阻塞也有预设上限,不会彼此影响,更不会对整个ServiceA服务造成影响。
2、使用
演示操作在Robbin基础上进行,Robbin教程可参考:http://t.csdn.cn/ogFCg
。
详细演示代码:https://gitee.com/micro_service_xk/netflix-cloud-demo.git user-service-hystix模块
①引入hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
②开启hystrix
@EnableDiscoveryClient //开启Eureka客户端
@EnableCircuitBreaker //开启hystrix
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
服务降级演示
针对局部代码配置
@GetMapping("{userId}")
@ResponseBody
/**
* 默认1s远程服务未响应将触发降级,将直接调用本地的降级逻辑,迅速响应用户
*/
@HystrixCommand(fallbackMethod = "queryByIdFallback",commandProperties = {
//配置本方法中远程服务调用服务降级为3s,仅对本方法有效
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public User queryById(@PathVariable("userId") Integer id){
User user = new User(1,"张三","成都市");
//RestTemplate直接使用服务名,进行远程接口调用
String url = "http://order-service/order/1";
Order order = restTemplate.getForObject(url, Order.class);
user.setOrder(order);
return user;
}
/**
* 本地的降级方法,需要和原方法返回相同类型
*/
public User queryByIdFallback(Integer id){
log.error("远程服务order-service调用失败,触发本地降级逻辑");
User user = new User(1,"张三","成都市");
return user;
}
针对全局配置
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000 # 设置hystrix的超时时间为2000ms,对所有远程服务调用生效
熔断策略配置
#熔断策略信息一般采用默认值,不作配置修改
hystrix:
command:
default:
circuitBreaker:
requestVolumeThreshold: 10 # 触发熔断最小请求次数,默认值是20
errorThresholdPercentage: 50 # 触发熔断错误比例阈值,默认值50%
sleepWindowInMilliseconds: 10000 # 熔断后休眠时长,默认值5秒