Hystrix断路器
- 一、Hystrix断路器概念
- 二、Hystrix重要概念
-
- 1、服务降级
- 2、服务熔断
- 3、服务限流
- 二、Hystrix配置
- 三、消费端配置
- 三、服务端(提供者)服务降级
- 四、客户端(消费端)服务降级
- 五、服务熔断
-
- 1、断路器三个重要的参数:
- 总结
一、Hystrix断路器概念
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等。Hystriix能够保证在一个依赖问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
二、Hystrix重要概念
1、服务降级
当服务单元发生故障时,会向调用方返回一个符合预期的,可处理的备选方案。程序运行异常、超时、服务熔断触发服务降级、线程池/信号量打满等情况都有可能触发服务降级
2、服务熔断
类比于保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法给出友好的响应。
3、服务限流
秒杀、高并发等操作中,同时的发出请求,会对服务器造成过大的压力。服务限流就是为避免这种情况而生,严禁所有的请求同时涌来,而是使请求排队,规定一秒内处理多少个请求,有序进行。
二、Hystrix配置
消费者端配置:
<!--hystrix服务熔断-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
控制器:
/**
* 服务熔断(正常访问)
* @param id 测试id
* @return 返回
*/
@GetMapping("/payment/hystrix/ok")
public String paymentInfoOk(Long id){
return "线程池:"+Thread.currentThread().getName()+" paymentInfo_OK id: "+id+"\t正常访问!";
}
/**
* 服务熔断(模拟程序出错)
* @param id 测试id
* @return 返回
*/
@GetMapping("/payment/hystrix/timeOut")
public String paymentInfoTimeOut(Long id){
int timeNum = 3;
//休眠timeNum秒钟
try {
TimeUnit.SECONDS.sleep(timeNum);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:"+Thread.currentThread().getName()+" paymentInfo_Timeout id: "+id+"\t耗时"+timeNum+"秒钟";
}
启动消费端自测:
在非高并发的条件下,勉强可用,使用Jmeter模拟高并发场景,注意:前提:使用jmeter工具之前需要安装java.并配置好java的环境变量,官网(https://jmeter.apache.org/download_jmeter.cgi)
模拟测试20000并发请求:
再次访问之前的延时方法,可用发现我们的服务严重被拖慢,如果你的并发在设置大一些,可能就会导致服务雪崩不可用。
三、消费端配置
消费端业务类:
@FeignClient(value = "provider-service")
public interface PaymentFeignService {
@GetMapping("/payment/hystrix/ok")
String paymentInfoOk(Long id);
@GetMapping("/payment/hystrix/timeOut")
String paymentInfoTimeOut(Long id);
}
控制器:
@GetMapping("/payment/hystrix/ok")
String paymentInfoOk(@RequestParam("id") Long id);
@GetMapping("/payment/hystrix/timeOut")
String paymentInfoTimeOut(@RequestParam("id") Long id);
测试:
8001客户端响应缓慢,超时导致服务变慢,出错(服务宕机,程序运行出错)需要限流:
三、服务端(提供者)服务降级
服务提供者控制器:
/**
* 服务熔断(模拟程序出错)
* @param id 测试id
* @return 返回
*/
@GetMapping("/payment/hystrix/timeOut")
@HystrixCommand(fallbackMethod = "paymentInfoTimeOutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentInfoTimeOut(Long id){
int timeNum = 5;
//休眠timeNum秒钟
//模拟程序报错
//int n = 10 / 0;
try {
TimeUnit.SECONDS.sleep(timeNum);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info(Thread.currentThread().getName());
return "线程池:"+Thread.currentThread().getName()+" paymentInfo_Timeout id: "+id+"\t耗时"+timeNum+"秒钟";
}
public String paymentInfoTimeOutHandler(Long id){
return "线程池:"+Thread.currentThread().getName()+" paymentInfo_Timeout id: "+id+"\t进入服务降级处理";
}
@HystrixCommand 注解 熔断、服务降级,fallbackMethod:标记的是捕获异常时需要执行的方法,方法名称跟value值要一样,我这里是paymentInfoTimeOutHandler。
Hystrix降级处理超时时间设置execution.isolation.thread.timeoutInMilliseconds,设置超时时间3秒钟
服务提供者启动类添加注解@EnableCircuitBreaker //激活服务降级
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker //激活服务降级
@MapperScan("com.dtydf.springcloud.dao")
public class PaymentAppMain {
public static void main(String[] args) {
SpringApplication.run(PaymentAppMain.class,args);
}
}
测试:
再看控制台打印:
再来模拟程序运行出错:
@GetMapping("/payment/hystrix/timeOut")
@HystrixCommand(fallbackMethod = "paymentInfoTimeOutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentInfoTimeOut(Long id){
//int timeNum = 5;
//休眠timeNum秒钟
//模拟程序报错
int n = 10 / 0;
/*try {
TimeUnit.SECONDS.sleep(timeNum);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
log.info(Thread.currentThread().getName());
return "线程池:"+Thread.currentThread().getName()+" paymentInfo_Timeout id: "+id+"\t服务正常";
}
public String paymentInfoTimeOutHandler(Long id){
return "线程池:"+Thread.currentThread().getName()+" paymentInfo_Timeout id: "+id+"\t进入服务降级处理";
}
加入消费者服务,先改为5秒钟正常,服务提供为三秒,在提供者服务端为正常:
测试:
四、客户端(消费端)服务降级
<!--hystrix服务熔断-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
feign: #支持服务熔断
hystrix:
enabled: true
@EnableHystrix //启动服务熔断
public class OrderAppMain {
public static void main(String[] args) {
SpringApplication.run(OrderAppMain.class,args);
}
}
控制器,设置1.5秒耗时等待:
@GetMapping("/consumer/payment/hystrix/timeOut")
@HystrixCommand(fallbackMethod = "paymentInfoTimeOutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
public String paymentInfoTimeOut(@RequestParam("id") Long id){
return paymentFeignService.paymentInfoTimeOut(id);
}
public String paymentInfoTimeOutHandler(@RequestParam("id") Long id){
return "客户端开启服务熔断,对方支付繁忙,请在5秒钟后重试!";
}
测试:
程序出错,模拟int n = 10 /0,程序出错,服务降级:
@GetMapping("/consumer/payment/hystrix/timeOut")
@HystrixCommand(fallbackMethod = "paymentInfoTimeOutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
public String paymentInfoTimeOut(@RequestParam("id") Long id){
int n = 10 /0;
return paymentFeignService.paymentInfoTimeOut(id);
}
public String paymentInfoTimeOutHandler(@RequestParam("id") Long id){
return "客户端8001开启服务熔断,对方支付繁忙,请在5秒钟后重试!亦或自己出错请检查自己";
}
全局配置服务降级:
@DefaultProperties(defaultFallback = “paymentGlobleHandler”) 通用的和专用的分开,避免代码膨胀,合理减少代码量
@GetMapping("/consumer/payment/hystrix/timeOut")
@HystrixCommand
public String paymentInfoTimeOut(@RequestParam("id") Long id){
//模拟程序出错
int n = 10 /0;
return paymentFeignService.paymentInfoTimeOut(id);
}
测试:
通配fallback解耦服务降级处理:
/**
* @description: 解耦处理服务降级
* @author: ydf
* @date: 2021/1/1 23:16
* @version: v1.0
*/
@Component
public class PaymentFeignServiceFallBack implements PaymentFeignService{
@Override
public CommentResult<Payment> getPaymentById(Long id) {
return new CommentResult<>(20001,"错误",null);
}
@Override
public String paymentConsul() {
return "---------------对宕机的服务进行服务降级处理-----------";
}
@Override
public String paymentFeignTimeout() {
return "---------------对宕机的服务进行服务降级处理-----------";
}
@Override
public String paymentInfoOk(Long id) {
return "---------------对宕机的服务进行服务降级处理-----------";
}
@Override
public String paymentInfoTimeOut(Long id) {
return "---------------对宕机的服务进行服务降级处理-----------";
}
}
使服务提供者9001宕机,8001调用服务进入服务降级处理,测试方法:
/**
* 服务熔断-服务调用测试
* @param id 测试id
* @return 返回
*/
@GetMapping("/consumer/payment/hystrix/ok")
public String paymentInfoOk(@RequestParam("id") Long id){
return paymentFeignService.paymentInfoOk(id);
}
五、服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制。 当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回”错误”的响应信息。当检测到该节点微服务响应正常后恢复调用链路,在SpringCloud框架机制通过Hystrix实现,Hystrix会监控微服务见调用的状况,当失败的调用到一个阈值,缺省是5秒内20次调用失败就会启动熔断机制,熔断机制的注解是@HystrixCommand
控制器代码:
/**
* 服务熔断测试
* @param id 参数id
* @return 返回
*/
@GetMapping("/payment/hystrix/fus/{id}")
@HystrixCommand(fallbackMethod = "paymentFusingFallBack",commandProperties = {
//是否开启断路器
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
//请求次数
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
//时间窗口期
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
//失败率达到多少后跳闸
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),
})
public String paymentFusing(@PathVariable("id") Long id){
if(id < 0){
throw new RuntimeException("************id,不能为负数");
}
String uuid = IdUtil.simpleUUID();
return Thread.currentThread().getName()+"\t" + "订单号===" + uuid;
}
public String paymentFusingFallBack(@PathVariable("id") Long id){
return "id不能为负数,请稍后重试!";
}
启动服务测试:正确则成功,错误则走FallBack服务降级处理:
继续点击错误率达到60%以上,就会进入服务熔断,即使当前请求为正确也不会立刻恢复,我们再次请求发现:
只要当参数正确大于60%以后,慢慢的,我们又从错误的恢复到了正确的状态:
1、断路器三个重要的参数:
如图所示,在微服务中使用Hystrix 作为断路器时,通常涉及到一下三个重要的指标参数(这里是写在@HystrixProperties注解中,当然实际项目中可以全局配置在yml或properties中)
1、circuitBreaker.sleepWindowInMilliseconds
断路器的快照时间窗,也叫做窗口期。可以理解为一个触发断路器的周期时间值,默认为10秒(10000)。
2、circuitBreaker.requestVolumeThreshold
断路器的窗口期内触发断路的请求阈值,默认为20。换句话说,假如某个窗口期内的请求总数都不到该配置值,那么断路器连发生的资格都没有。断路器在该窗口期内将不会被打开。
3、circuitBreaker.errorThresholdPercentage
断路器的窗口期内能够容忍的错误百分比阈值,默认为50(也就是说默认容忍50%的错误率)。打个比方,假如一个窗口期内,发生了100次服务请求,其中50次出现了错误。在这样的情况下,断路器将会被打开。在该窗口期结束之前,即使第51次请求没有发生异常,也将被执行fallback逻辑。
综上所述,在以上三个参数缺省的情况下,Hystrix断路器触发的默认策略为:
在10秒内,发生20次以上的请求时,假如错误率达到50%以上,则断路器将被打开。(当一个窗口期过去的时候,断路器将变成半开(HALF-OPEN)状态,如果这时候发生的请求正常,则关闭,否则又打开)
总结
Hystrix是一个延迟和容错库,旨在隔离对远程系统,服务和第三方库的访问点,停止级联故障,并在不可避免发生故障的复杂分布式系统中实现弹性。