一、Hystrix 服务熔断

1、熔断机制概述:

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

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

2、案例:

Controller 调用 Service,请求数10次内出现6次以上错误,就会触发熔断,熔断后正确的请求也不能立刻被响应,而是缓慢、正确率高了才响应。

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

3、总结:

熔断类型

  • 熔断打开
    请求不再进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入半熔断状态
  • 熔断关闭
    熔断关闭不会对服务进行调用
  • 熔断半开
    部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断

4、断路器在什么情况下开始起作用

设计到断路器的三个重要参数:快照时间窗、请求总数阈值、错误百分比阈值

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

断路器开启或关闭的条件

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

断路器打开之后

  1. 再有请求调用的时候,将不会调用主逻辑,而是直接调用降级fallback。通过断路器,实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟的效果。
  2. 原来的主逻辑要如何恢复呢?
    对于这一问题,hystrix也为我们实现了自动恢复功能
    当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,当休眠时间窗到期,熔断器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。

5、Hystrix相关配置:

具体配置参考:com.netflix.hystrix.HystrixCommandProperties 中包含许多默认配置
参考:Hystrix配置详解(Finchley.RC2版本)

    @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"), //失败率达到多少后跳闸
    })
  @HystrixCommand(
            commandProperties = {
   
                    //没置隔离策略,THREAD表示线程池SEMAPHORE:信号池隔离
                    @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
                    //当隔离策略选择信号池隔离的时候,用来设置信号地的大小(最大并发数)
                    @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10"),
                    //配置命令执行的超时时间
                    @HystrixProperty(name = "execution.isolation.thread.TimeoutInMilliseconds", value = "10"),
                    //是否启用超时时/间
                    @HystrixProperty(name = "execution.timeout.enabled", value = "true"),
                    //执行超时的时候是否中断
                    @HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "true"),
                    //执行被取消的时候是否中断
                    @HystrixProperty(name = "execution.isolation.thread.interruptOnCance1", value = "true"),
                    //允许回调方法执行的最大并发数
                    @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "10"),
                    //服务降级是否启用,是否执行回调函数
                    @HystrixProperty(name = "fallback.enabled", value = "true"),
                    //该属性用来设置在踉动时间窗中,断路器熔断的最小请求数。例如,默认该值为20 的时候,
                    //如果b动时间窗〈默认10秒)内仅收到了19个请求,即使这19个请求都失败了,断路器也不会打开。
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
                    //该属性用来没置在滚动时间窗中,表示在滚动时间窗中,在请求数量超过
                    // circuitBreaker.RequestVolumeThreshold 的情况下,如果错误请求数的百分比超过50,
                    // 就把断路器没置为“打开”状态,否则就没置为“关闭”状态。
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
                    //该属性用来设置当断路器打开之后的休眠时间窗。休眠时间窗结束之后,
                    //会将断路器置为“半开”状态,尝式熔断的请求命令,如果依然失败就将断路器继续设置为“打开”状态,
                    //如果成功就设置为“关闭”状态。
                    @HystrixProperty(name = "circuitBreaker.SleepWindowInMilliseconds", value = "5000"),
                    //断路器强制打开
                    @HystrixProperty(name = "circuitBreaker.forceOpen", value = "false"),
                    //断路器强制关闭
                    @HystrixProperty(name = "circuitBreaker.forceClosed", value = "false"),
                    //滚动时间窗设置,该时间用于断路器判断健康度时需要收集信息的持续时间
                    @HystrixProperty(name = "metrics.rollingStats.timeinMilliseconds", value = "10000"),
                    //该属性用来没置滚动时间窗统计指标信息时划分"桶"的数量,断路器在收集指标信息的时候会根据
                    //设置的时间窗长度拆分成多个“桶”来累计各度量值,每个"桶"记录了一段时间内的采集指标。
                    //比如10秒内拆分成10个"桶"收集这样,所以timeInMilliseconds必须能被 numBuckets 整除。否则会抛异常
                    @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10"),

                    @HystrixProperty(name = "metrics.rollingPercentile.bucketSize", value = "100"),
                    //该属性用来设置采集影响断路器状态的健康快照(请求的成功、错误百分比)的间隔等待时间。
                    @HystrixProperty(name = "metrics.healthSnapshot.IntervalInMilliseconds", value = "500"),
                    //是否开启请求缓存
                    @HystrixProperty(name = "requestCache.enabled", value = "true"),
                    // HystrixCommand的执行和喜件是否打印日志到 HystrixRequestLog中
                    @HystrixProperty(name = "requestLog.enabled", value = "true"),
            },
            threadPoolProperties = {
   
                    //该参数用来设置执行命令线程池的核心线程数,该值也就是命令执行的最大并发量
                    @HystrixProperty(name = "coreSize", value = "10"),
                    //该参数用来设置线程池的最大队列大小。当设置为-1时,线程她将使用SynchronousQueue 实现的队列,
                    // 否则将使用LinkedBLockingQueue实现的队列。
                    @HystrixProperty(name = "maxQueueSize", value = "-1"),
                    //该参数用来为队列设置拒绝阈值。通过该参数,即使队列没有达到最大值也能拒绝请求。
                    //该参数主要是对LinkedBLockingQueue 队列的补充,因为LinkedBLockingQueue
                    //队列不能动态修改它的对象大小,而通过该属性就可以调整拒绝请求的队列大小了。
                    @HystrixProperty(name = "queueSizeRejectionThreshold", value = "5")
            }
    )



二、工作原理

官网介绍:工作原理
参考文章:防雪崩利器:熔断器 Hystrix 的原理与使用
参考文章:Hystrix原理与实战
蓝色线(invoke path)为调用路线
红色线(return path)为返回路线

  1. 创建Hystrix Command (用在依赖的服务返回单个操作结果的时候)或HystrixObserableCommand (用在依赖的服务返回多个操作结果的时候)对象。 我们示例中使用的是注解版@HystrixCommand
  1. 命令执行。其中 HystrixComand实现了下面前两种执行方式;而HtytixOCocevabeComand 实现了后两种协行方式; execute():同步执行,从依确的服务返回一个单一的结果对象,或是在发生错误的时候抛出异常。queve():异步执行,直接返回一个Future对象,其中包含了的务执行结束时要返回的单一结果对象。observe():返回Observable则象,它代表了操作的多个结果,它是一个Hot Obserable(不论"事件源"是否有订阅者,都会在创建后对事件进行发布,所以对于Hct Observable的每一个订阅者*都有可能是从事件震”的中途开始的,并可能只是看到了整个操作的同部随程),toOBservale():同样会返回Observable对象,也代表了操作的多个结果,但它返回的是一个Cod Obosevabie (没有“切闲者’的时候并不会发布事件,而是进行等待。直到有"订阅者"之后才发布事件,所以对于Cold Observable的订阅者,它可以保证从一开始看到整个操作的全部过程)
  1. 若当前命令的请求缓存功能是被启用的,并且该命令缓存命中,那么缓存的结果会立即以Observable对象的形式返回。
  1. 检查断路是否为打开状态,如果断路器是打开的,那么Hystrix 不会执行命令,而是转接到 fallback处理逻辑(第8步);如果断路器是关闭的,枪检查是否有可用资源来执行命令(第5步)。
  1. 线找程池/(请求队列)信号显是否占满。如果命分依船服务的专有线程也和请求队列,或者信号量(不使且战程地的时候)已经被占满,那么 hytix也不会执行命令,而是转接到 fllack处理过辑(第8步) 。
  1. Hystrix 会根据我们编写的方法来决定采取什么样的方式去请求依赖服务。HystrixCommand.run() :返回一个单一的结果,或者抛出异常。HystrixObservableCommand.construct:返回一个Observable对象来发射多个结果,或通过onError发送错误通知。
  1. Hystrix会将“成功、“失败”、“短绝”、“超时"等信息报告洽断路器,而断路器会维炉一组大数器来统计这些数据。断路器会使用这些然数据来决定是否要将断路器打开,来对某个依赖服务的清求进行"熔断/短路"。
  1. 当命令执行关败的时候,Hystrix会进入fillack尝试回退处理,我们通常也称该操作为波务降级"。而能够引越迢l务烽没处磺的情况有下面加种:第4步、当前命令处于e断新/5路"吠态,断路最是打开的时候。第5步:当前命令的钱程池、请求队列或者信号量被占满的时候。第6步:HystrixObservableCommand.construct()或HystrixComnand.run()抛出异常的时候。
  1. 当Hystrix命令执行成功之后,它会将处理结果直接返回或是以Observable 的形式返回.

三、Hystrix 图形化Dashboard搭建及监控测试

1、概述:

除了隔离依赖服务的调用意外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续的记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix 通过 hystrix-metrics-event-stream项目实现了对以上指标的监控。SpringCloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。

2、搭建:

  1. 新建module cloud-consumer-hystrix-dashboard9001
  2. pom.xml
<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-hystrix-dashboard9001</artifactId>

    <dependencies>
    <!-- hystrix-dashboard 仪表板监控需要导入的场景启动器-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</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>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>	
  1. application.yml
server:
  port: 9001
  1. 主启动
//加注解@EnableHystrixDashboard
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
   
    public static void main(String[] args) {
   
        SpringApplication.run(HystrixDashboardMain9001.class,args);
    }
}
  1. 所有provider 微服务提供类都需要监控依赖配置
<dependency>
    <groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  1. 启动 9001 该微服务后续将监控provider 微服务,出现下面图标搭建成功

http://localhost:9001/hystrix

无法连接远程流 请继续往下看

  1. 服务监控hystrixDashboard

新版本Hystrix需要在被监控的服务中主启动类中指定监控路径

//主启动类添加代码
    /** * 此配置是为了服务监控而配置,与服务容错本身无关,SpringCloud升级后的坑 * ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream", * 只要在自己的项目里配置上下面的servlet就可以了 */
    @Bean
    public ServletRegistrationBean getServlet(){
   
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }

127.0.0.7:8001/hystrix.stream

9001监控8001,启动 监控的provider 8001,点击上图的monitor stream测试

当请求次数越多,流量越多,图中小球会越来越大,没有触发熔断时,Circuit 显示 Closed ,触发熔断显示Open

图解:


四、限流

后面高级篇讲解alibaba的Sentinel说明
Hystrix 以后用到再补充