天天看点

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

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+"秒钟";
}
           

启动消费端自测:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结
SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

在非高并发的条件下,勉强可用,使用Jmeter模拟高并发场景,注意:前提:使用jmeter工具之前需要安装java.并配置好java的环境变量,官网(https://jmeter.apache.org/download_jmeter.cgi)

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

模拟测试20000并发请求:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结
SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结
SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

再次访问之前的延时方法,可用发现我们的服务严重被拖慢,如果你的并发在设置大一些,可能就会导致服务雪崩不可用。

三、消费端配置

消费端业务类:

@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);
           

测试:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

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);
    }
}
           

测试:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

再看控制台打印:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

再来模拟程序运行出错:

@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进入服务降级处理";
 }
           
SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

加入消费者服务,先改为5秒钟正常,服务提供为三秒,在提供者服务端为正常:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

测试:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

四、客户端(消费端)服务降级

<!--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秒钟后重试!";
}
           

测试:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

程序出错,模拟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秒钟后重试!亦或自己出错请检查自己";
}
           
SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

全局配置服务降级:

@DefaultProperties(defaultFallback = “paymentGlobleHandler”) 通用的和专用的分开,避免代码膨胀,合理减少代码量
SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结
@GetMapping("/consumer/payment/hystrix/timeOut")
@HystrixCommand
public String paymentInfoTimeOut(@RequestParam("id") Long id){
    //模拟程序出错
    int n = 10 /0;
    return paymentFeignService.paymentInfoTimeOut(id);
}
           

测试:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

通配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 Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

五、服务熔断

熔断机制是应对雪崩效应的一种微服务链路保护机制。 当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回”错误”的响应信息。当检测到该节点微服务响应正常后恢复调用链路,在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服务降级处理:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结
SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

继续点击错误率达到60%以上,就会进入服务熔断,即使当前请求为正确也不会立刻恢复,我们再次请求发现:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

只要当参数正确大于60%以后,慢慢的,我们又从错误的恢复到了正确的状态:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结

1、断路器三个重要的参数:

SpringCloud Hoxton版微服务- Hystrix(服务降级、服务熔断)一、Hystrix断路器概念二、Hystrix重要概念二、Hystrix配置三、消费端配置三、服务端(提供者)服务降级四、客户端(消费端)服务降级五、服务熔断总结
如图所示,在微服务中使用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是一个延迟和容错库,旨在隔离对远程系统,服务和第三方库的访问点,停止级联故障,并在不可避免发生故障的复杂分布式系统中实现弹性。

继续阅读