7、Hystrix断路器(个人学习笔记)

1、Hystrix概述

分布式系统面临的问题

复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。

什么服务雪崩?

多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的 扇出。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的 雪崩效应

对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和,比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。所以,通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者雪崩

Hystrix是什么

Hystrix是一个用于处理分布式系统的 延迟和容错 的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,已提高分布式系统的弹性。

断路器 本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack)而不是长时间的等待或者抛出调用方法无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

Hystrix能干嘛

2、Hystrix重要概念

服务降级(系统不可用时,不让客户端等待,立刻返回一个友好提示 )

  • 服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示

  • 那么哪些情况会需要降级呢

    • 程序运行异常
    • 请求超时
    • 服务熔断触发服务降级
    • 线程池/信号量打满也会导致服务降级

服务熔断

  • 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示

  • 过程:服务的降级 -> 进而熔断 -> 恢复调用链路

服务限流

秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行。

3、Hystrix支付微服务构建

为了方便,我们这里将eureka改为单机版的进行操作

新建项目cloud-provider-hystrix-payment8001

修改pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.spring.study</groupId>
    <artifactId>cloud-provider-hystrix-payment8001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!--   引入自己定义的api通用包,可以使用Paymeny支付Entity     -->
        <dependency>
            <groupId>com.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

写yml

server:
  port: 8001

spring:
  application:
    name: cloud-provider-hystrix-payment

eureka:
  client:
    #是否从EurekaServer抓取已有的注册信息,默认是true。单节点无所谓,集群必须设置为true才能配合Ribbon使用负载均衡
    fetch-registry: true
    #表示是否将自己注册进EurekaServer中,默认是true
    register-with-eureka: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka

主启动类

@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentHystrixMain8001.class, args);
    }
}

业务类编写

  • service业务类
@Service
public class PaymentService {

    /**
     * 正常访问,肯定OK
     *
     * @param id
     * @return
     */
    public String PaymentInfo_OK(Integer id) {
        return "线程池:" + Thread.currentThread().getName() + "paymentInfo_OK,id" + id + "\t" + "O(∩_∩)O哈哈~";
    }

    /**
     * 等待时间为3秒
     *
     * @param id
     * @return
     */
    public String PaymentInfo_TimeOut(Integer id) {
        int timeNumber = 3;
        try {
            TimeUnit.SECONDS.sleep(timeNumber);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + "paymentInfo_TimeOut,id" + id + "\t" + "O(∩_∩)O哈哈~" + "耗时(秒)" + timeNumber;
    }
}
  • controller业务类
@RestController
@Slf4j
public class PaymentController {

    @Resource
    private PaymentService paymentService;

    @Value("$(server.port)")
    private String serverPort;

    /**
     * 正常访问
     *
     * @param id
     * @return
     */
    @GetMapping("payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id) {
        String result = paymentService.PaymentInfo_OK(id);
        log.info("***result" + result);
        return result;
    }

    /**
     * 超时3秒
     *
     * @param id
     * @return
     */
    @GetMapping("payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
        String result = paymentService.PaymentInfo_TimeOut(id);
        log.info("***result" + result);
        return result;
    }

}

启动测试接口

  • 先启动eureka7001

  • 在启动Hystrix支付微服务cloud-provider-hystrix-payment8001

  • 结果

    • http://localhost:8001/payment/hystrix/ok/1接口可以正确访问并立即响应
    • http://localhost:8001/payment/hystrix/timeout/1每次调用耗费3秒钟

以上述为根基平台,从正确 -> 错误 -> 降级熔断 -> 恢复进行操作。

4、使用JMeter模拟高并发压测

上述在非高并发下,还是可以出结果的,勉强满足。

JMeter压测测试

JMeter官网: JMeter官网

  • 开启JMeter

在这里插入图片描述

  • 设置线程数为200,循环次数为100

在这里插入图片描述

  • 设置Http请求

在这里插入图片描述

  • 启动线压测

在这里插入图片描述

  • 结论

  • http://localhost:8001/payment/hystrix/ok/1请求也开始变得缓慢

  • 这里还是服务提供者8001自己测试,假如此时外部的消费者80也来访问,那消费者只能干等,最终导致消费端80不满意,服务端8001直接被拖慢。

为什么会被卡死

SpringBoot默认集成了tomcat(Tomcat线程池默认10个),现在tomcat的默认的工作线程数被打满了,没有多余的线程来分解压力和处理。

5、新建80消费者

创建cloud-consumer-feign-hystrix-order80消费者服务

修改pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-feign-hystrix-order80</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--   引入自己定义的api通用包,可以使用Paymeny支付Entity     -->
        <dependency>
            <groupId>com.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

写yml文件

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

主启动类

@SpringBootApplication
@EnableFeignClients //激活Feign
public class OrderHystrixMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderHystrixMain80.class, args);
    }
}

业务类编写

  • PaymentHystrixService
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {

    @GetMapping("payment/hystrix/ok/{id}")
    String paymentInfo_OK(@PathVariable("id") Integer id);

    @GetMapping("payment/hystrix/timeout/{id}")
    String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
  • OrderHystrixController
@RestController
@Slf4j
public class OrderHystrixController {

    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfo_OK(id);
    }

    @GetMapping("consumer/payment/hystrix/timeout/{id}")
    public  String paymentInfo_TimeOut(@PathVariable("id") Integer id){
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }
}

正常测试

  • 访问http://localhost:8001/payment/hystrix/ok/1,响应耗时极短
  • 访问http://localhost/consumer/payment/hystrix/ok/1,响应耗时也极短

那么此时我们再次使用2万个线程压测8001

  • 再次访问http://localhost/consumer/payment/hystrix/ok/1,响应耗时变的延长

  • 原因:8001同一层次的其它接口服务被困死,因为tomcat线程池里面的工作线程已经被挤占完毕。

  • 正因为有上述故障或不佳表现才有我们的 降级/容错/限流等技术诞生

6、降级容错解决的要求

  • 现象: 超时导致服务器变慢(转圈) 解决方案: 超时不再等待
  • 现象: 出错(宕机或程序运行出错) 解决方案: 出错要有兜底

解决

  • 对方服务(8001)超时了,但是调用者(80)不能一直卡死等待,必须有服务降级
  • 对方服务(8001)宕机了,但是调用者(80)不能一直卡死等待,必须有服务降级
    对方服务(8001)OK,但是调用者(80)自己出故障或有自我要求(自己的等待时间小于服务提供者),自己处理降级。

7、服务降级

  • 官网的使用方式
    在这里插入图片描述

降级配置(这里我们用配置替代编码 ==> @HystrixCommand)

  • 我们先从8001自身找问题:可以设置自身调用的超时时间的峰值,峰值内可以正常运行,但是超过了峰值,就需要有兜底的方法进行处理,作服务降级fallback

那么8001Fallback怎么玩呢

  • 业务类启用@HystrixCommand

@HystrixCommand报异常后如何处理 :—旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法

    /**
     * 等待时间为3秒
     * 该方法出问题后去找兜底的方法fallbackMethod = "PaymentInfo_TimeOutHandler"
     * execution.isolation.thread.timeoutInMilliseconds:是指当前线程的超时时间
     *
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "PaymentInfo_TimeOutHandler", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
    public String PaymentInfo_TimeOut(Integer id) {
        int timeNumber = 5;
        try {
            TimeUnit.SECONDS.sleep(timeNumber);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + "paymentInfo_TimeOut,id" + id + "\t" + "O(∩_∩)O哈哈~" + "耗时(秒)" + timeNumber;
    }

    /**
     * 兜底的方法
     *
     * @param id
     * @return
     */
    public String PaymentInfo_TimeOutHandler(Integer id) {
        return "线程池:  " + Thread.currentThread().getName() + "  8001系统繁忙或者运行报错,请稍后再试,id:  " + id + "\t" + "o(╥﹏╥)o";
    }
  • 主启动类激活
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class PaymentHystrixMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentHystrixMain8001.class, args);
    }
}

测试结果,线程睡眠时间是5秒,等待时间是3秒,超过3秒就报错(走兜底方法)

在这里插入图片描述

那么80订单微服务Fallback怎么玩呢

  • 开启hystrix
server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

#开启
feign:
  hystrix:
    enabled: true
  • 在主动类上添加注解激活Hystrix
@SpringBootApplication
@EnableFeignClients
@EnableHystrix //激活
public class OrderHystrixMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderHystrixMain80.class, args);
    }
}
  • 修改80业务类
@RestController
@Slf4j
public class OrderHystrixController {

    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfo_OK(id);
    }

    @GetMapping("consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
    })
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }

    /**
     * 报错后的托底方法
     *
     * @param id
     * @return
     */
    String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
        return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
    }
}
  • 测试(80端接受等待时间为1.5秒,超过1.5秒就会报错,而8001支付端在3秒内是正常的,超过5秒才会报错)
    在这里插入图片描述
  • 访问http://localhost/consumer/payment/hystrix/timeout/1,会发现报超时的错误。

问题和解决方法

通过编写代码,会发现每个业务方法对应一个兜底方法,会使得代码膨胀,臃肿,那么怎么解决呢?

解决方法1:(通用的和独享的各自分开,避免了代码膨胀,合理减少了代码量)

  • 使用注解@DefaultProperties(defaultFallback = "") 可以统一跳转到统一的处理结果页面
  • 编写统一的兜底方法
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "paymentGlobalFallbackMethod")
public class OrderHystrixController {

    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfo_OK(id);
    }

    @GetMapping("consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }

    /**
     * 报错后的托底方法
     *
     * @param id
     * @return
     */
    String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
        return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
    }

    /**
     * 全局的fallback方法
     */
    public String paymentGlobalFallbackMethod() {
        return "Global异常处理信息,请稍后再试,/(ToT)/~~";
    }
}
  • 启动项目,访问http://localhost/consumer/payment/hystrix/timeout/1,已经跳转到了我们定义的通用兜底方法
    在这里插入图片描述

解决方法2:统一和自定义的分开,代码混乱

  • 服务降级,客户端去调用服务端,碰上服务端宕机或关闭
  • 本次案例服务降级处理是在客户端80实现完成的,与服务端8001没有关系,只需要为Feign客户端定义的接口 添加一个服务降级处理的实现类即可实现解耦
  • 未来我们会遇到的异常
    • 运行
    • 超时
    • 宕机

修改cloud-consumer-feign-hystrix-order80微服务

  • 根据cloud-consumer-feign-hystrix-order80已经有的PaymentHystrixService接口,
    重新新建一个类(PaymentFallbackService)实现该接口,统一为接口里面的方法进行异常处理。
@component//Spring容器扫描
public class PaymentFallbackService implements PaymentHystrixService{
    @Override
    public String paymentInfo_OK(Integer id) {
        return "paymentInfo_OK,o(╥﹏╥)o";
    }

    @Override
    public String paymentInfo_TimeOut(Integer id) {
        return "paymentInfo_OK,o(╥﹏╥)o";
    }
}
  • yml文件中添加配置(在Fegin中开启Hystrix
feign:
  hystrix:
    enabled: true
  • 修改PaymentHystrixService接口
/**
 * fallback指定服务降级的方法
 */
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {

    @GetMapping("payment/hystrix/ok/{id}")
    String paymentInfo_OK(@PathVariable("id") Integer id);

    @GetMapping("payment/hystrix/timeout/{id}")
    String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
  • 测试
    • 先启动eureka

    • 在启动8001微服务

    • 正常访问测试 http://localhost/consumer/payment/hystrix/ok/1
      在这里插入图片描述

    • 此时关闭8001微服务,再次访问
      在这里插入图片描述

    • 结果客户端自己去调用提示,此时服务端provider已经down了,但是我们 做了服务降级处理,让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器。

8、服务熔断

类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示 ==> (服务的降级->进而熔断->恢复调用链路)

Martin Fowler

在这里插入图片描述

熔断机制概述

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

  • Spring Cloud框架中,熔断通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是@HystrixCommand

在这里插入图片描述

实操

  • 修改cloud-provider-hystrix-payment8001微服务

  • 修改PaymentService

@Service
public class PaymentService {
    /**
     * 服务熔断
     */
    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback", 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 paymentCircuitBreaker(@PathVariable("id") Integer id) {
        if (id < 0) {
            throw new RuntimeException("id不能是负数");
        }
        String serialNumber = UUID.randomUUID().toString();

        return Thread.currentThread().getName() + "\t" + "调用成功,流水号:" + serialNumber;
    }

    public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) {
        return "id不能是负数,请稍后再试" + id;
    }

}
  • 为什么配置这几个参数
    • The precise way that the circuit opening and closing occurs is as follows:

      • Assuming the volume across a circuit meets a certain threshold : HystrixCommandProperties.circuitBreakerRequestVolumeThreshold()
      • And assuming that the error percentage, as defined above exceeds the error percentage defined in : HystrixCommandProperties.circuitBreakerErrorThresholdPercentage()
      • Then the circuit-breaker transitions from CLOSED to OPEN.
      • While it is open, it short-circuits all requests made against that circuit-breaker.
      • After some amount of time (HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds()), the next request is let through. If it fails, the command stays OPEN for the sleep window. If it succeeds, it transitions to CLOSED and the logic in 1) takes over again.

HystrixCommandProperties配置类

在这里插入图片描述

  • 修改PaymentController
    /**
     * 服务熔断
     *
     * @param id
     * @return
     */
    @GetMapping("/payment/circuit/{id}")
    public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
        String result = paymentService.paymentCircuitBreaker(id);
        log.info("result" + result);
        return result;
    }
  • 测试
    • 正常访问http://localhost:8001/payment/circuit/1
      在这里插入图片描述

    • 错误访问http://localhost:8001/payment/circuit/-1
      在这里插入图片描述

    • 多次点击错误地址,开启服务熔断,然后慢慢正确,发现刚开始不满足条件,就算是正确的访问地址也不能进行。

服务熔断总结

  • 熔断类型

    • 熔断打开
      • 请求不在进行调用当前服务,内部设置时钟一般为MTTR(平均故障时间),当打开时长达到所设时钟则进入半熔断状态
    • 熔断关闭
      • 熔断关闭时不会对服务进行熔断
    • 熔断半开
      • 部分请求根据规则调用当前服务,如果请求成功且符合规则认为当前服务恢复正常,关闭熔断
  • 断路器的三个重要参数:快照时间窗,请求总数阀值,错误百分比阈值
    在这里插入图片描述

    • 快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒
    • 请求总数阀值:在快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次7,即使所有的请求都超时或其他原因失败,断路器都不会打开。
    • 错误百分比阀值:当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阀值情况下,这时候就会将断路器打开。

断路器开启或者关闭的条件

  • 达到以下阀值时,断路器将会开启
    • 当满足一定的阀值的时候(默认10秒内超过20个请求次数)
    • 当失败率达到一定值的时候(默认10秒内超过50%的请求失败)
  • 当开启的时候,所有请求都不会进行转发
  • 一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。

断路器打开之后

  • 再有请求调用的时候,将不会调用主逻辑,而是直接调用降级fallback。通过断路器,实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟的效果。

  • 原来的主逻辑要如何恢复呢(hystrix也为我们实现了自动恢复功能)? 当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,当休眠时间窗到期,断路器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值