Hystrix 概念

在微服务架构中,一个应用往往由多个服务组成,这些服务之间相互依赖,依赖关系错综复杂。 例如一个微服务系统中存在 A、B、C、D、E、F 等多个服务,它们的依赖关系如下图

画板

通常情况下,一个用户请求往往需要多个服务配合才能完成。如图所有服务都处于可用状态时,请求 1 需要调用 A、D、E、F 四个服务才能完成,请求 2 需要调用 B、E、D 三个服务才能完成,请求 3 需要调用服务 C、F、E、D 四个服务才能完成。 当服务 E 发生故障或网络延迟时,会出现以下情况:
  1. 即使其他所有服务都可用,由于服务 E 的不可用,那么用户请求 1、2、3 都会处于阻塞状态,等待服务 E 的响应。在高并发的场景下,会导致整个服务器的线程资源在短时间内迅速消耗殆尽。
  2. 所有依赖于服务 E 的其他服务,例如服务 B、D 以及 F 也都会处于线程阻塞状态,等待服务 E 的响应,导致这些服务的不可用。
  3. 所有依赖服务B、D 和 F 的服务,例如服务 A 和服务 C 也会处于线程阻塞状态,以等待服务 D 和服务 F 的响应,导致服务 A 和服务 C 也不可用。
从以上过程可以看出,当微服务系统的一个服务出现故障时,故障会沿着服务的调用链路在系统中疯狂蔓延,最终导致整个微服务系统的崩溃,这就是雪崩效应。为了防止此类事件的发生,微服务架构引入了“熔断器”的一系列服务容错和保护机制。

熔断器

熔断器一词来源物理学中的电路知识,它的作用是当线路出现故障时,迅速切断电源以保护电路的安全。 在微服务领域,与物理学中的熔断器作用相似,微服务架构中的熔断器能够在某个服务发生故障后,向服务调用方返回一个符合预期的、可处理的降级响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常。这样就保证了服务调用方的线程不会被长时间、不必要地占用,避免故障在微服务系统中的蔓延,防止系统雪崩效应发生。

Spring Cloud Hystrix

上面说了下微服务中存在的问题。那上方问题的解决方案正式本文学习的Hystrix。它是一款优秀的服务容错与保护组件。

Hystrix 是基于 Netflix 公司的开源组件 Hystrix 实现的,它提供了熔断器功能,能够有效地阻止分布式微服务系统中出现联动故障,以提高微服务系统的弹性。Spring Cloud Hystrix 具有服务降级、服务熔断、线程隔离、请求缓存、请求合并以及实时故障监控等强大功能。 在微服务系统中,Hystrix 能够帮助我们实现以下目标:
  • 保护线程资源:防止单个服务的故障耗尽系统中的所有线程资源。
  • 快速失败机制:当某个服务发生了故障,不让服务调用方一直等待,而是直接返回请求失败。
  • 提供降级(FallBack)方案:在请求失败后,提供一个设计好的降级方案,通常是一个兜底方法,当请求失败后即调用该方法。
  • 防止故障扩散:使用熔断机制,防止故障扩散到其他服务。
  • 监控功能:提供熔断器故障监控组件 Hystrix Dashboard,随时监控熔断器的状态。

Hystrix 服务降级

Hystrix 提供了服务降级功能,能够保证当前服务不受其他服务故障的影响,提高服务的健壮性。 服务降级的使用场景有以下 2 种:
  • 在服务器压力剧增时,根据实际业务情况及流量,对一些不重要、不紧急的服务进行有策略地不处理或简单处理,从而释放服务器资源以保证核心服务正常运作。
  • 当某些服务不可用时,为了避免长时间等待造成服务卡顿或雪崩效应,而主动执行备用的降级逻辑立刻返回一个友好的提示,以保障主体业务不受影响。
我们可以通过重写 HystrixCommand 的 getFallBack() 方法或 HystrixObservableCommand 的 resumeWithFallback() 方法,使服务支持服务降级。 Hystrix 服务降级 FallBack 既可以放在服务端进行,也可以放在客户端进行。Hystrix 会在以下场景下进行服务降级处理:
  • 程序运行异常
  • 服务超时
  • 熔断器处于打开状态
  • 线程池资源耗尽
下面我们就通过一个案例,分别演示下 Hystrix 服务端服务降级客户端服务降级

服务端服务降级

  1. 新建Hystrix降级模块 spring-cloud-provider-hystrix-9007pom.xml添加所需要的核心依赖
  1. <!--引入 Eureka Client 的依赖,将服务注册到 Eureka Server-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  5. </dependency>
  6. <!--hystrix 依赖-->
  7. <dependency>
  8. <groupId>org.springframework.cloud</groupId>
  9. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  10. <version>2.2.8.RELEASE</version>
  11. </dependency>

hystrix如果现在不写版本号,默认是会识别不到的,所以去查一下所需的版本显示声明就好

  1. 类路径(即 /resources 目录)下添加一个配置文件 <font style="color:rgb(68, 68, 68);">application.yml</font>,配置内容如
  1. server:
  2. port: 9007 #端口号
  3. spring:
  4. application:
  5. name: spring-cloud-provider-hystrix-9007 #对外暴露的微服务名称
  6. eureka:
  7. client: #将客户端注册到 eureka 服务列表内
  8. service-url:
  9. defaultZone: http://127.0.0.1:9001/eureka #这个地址是9001注册中心在 application.yml 中暴露出来额注册地址 (单机版)
  10. #defaultZone: http://eureka8999.com:8999/eureka/,http://eureka9000.com:9000/eureka/,http://eureka9001.com:9001/eureka/ #将服务注册到 Eureka Server 集群
  11. instance:
  12. instance-id: spring-cloud-provider-hystrix-9007 #自定义服务名称信息
  13. prefer-ip-address: true #显示访问路径的 ip 地址
  1. 创建服务BookService接,编写两个Hystrix正常和异常访问的方法用于测试
package com.chen.springcloudproviderhystrix9007.service;

public interface BookService {

    //hystrix 熔断器正常访问案例
    public String bookInfo_Ok(Integer id);

    //hystrix 熔断器超时案例
    public String bookInfo_Timeout(Integer id);
}
  1. 常见BookService接口的实现类 BookServiceImpl,实现如下:
package com.chen.springcloudproviderhystrix9007.service.impl;

import com.chen.springcloudproviderhystrix9007.service.BookService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class BookServiceImpl implements BookService {

    /**
     * 正常访问方法
     * @param id
     * @return
     */
    @Override
    public String bookInfo_Ok(Integer id) {
        return "线程池【" + Thread.currentThread().getName() + "】 bookInfo_Ok,id: 【" + id + "】";
    }

    /**
     * 一旦该方法失败并抛出了异常信息后,会自动调用  @HystrixCommand 注解标注的 fallbackMethod 指定的方法
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "book_TimeoutHandler",
            commandProperties =//规定 5 秒钟以内就不报错,正常运行,超过 5 秒就报错,调用指定的方法
                    {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")})
    @Override
    public String bookInfo_Timeout(Integer id) {
        int outTime = 6;
        try {
            TimeUnit.SECONDS.sleep(outTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池:【" + Thread.currentThread().getName() + "】  bookInfo_Timeout,id: 【" + id + "】耗时: " + outTime;
    }

    /**
     * 熔断调用的方法
     * @param id
     * @return
     */
    public String book_TimeoutHandler(Integer id) {
        return "系统异常请稍后再试!线程池:【" + Thread.currentThread().getName() + "】bookInfo_Timeout,id:【" + id + "】";
    }
}
我们可以看到 bookInfo_Timeout() 方法上使用 @HystrixCommand 注解,该注解说明如下:
  • 参数 fallbackMethod 属性用于指定降级方法。
  • 参数 <font style="color:rgb(68, 68, 68);">execution.isolation.thread.timeoutInMilliseconds</font> 用于设置自身调用超时时间的峰值,峰值内可以正常运行,否则执行降级方法
  1. 创建BookController,调用BookService查看结果
@RestController
@Slf4j
public class BookController {

    @Autowired
    private BookService bookService;

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

    @RequestMapping(value = "/book/hystrix/ok/{id}")
    public String bookInfo_Ok(@PathVariable("id") Integer id) {
        String result = bookService.bookInfo_Ok(id);
        log.info("端口号:" + serverPort + "result:" + result);
        return result + ",端口号:" + serverPort;
    }

    // Hystrix 服务超时降级
    @RequestMapping(value = "/book/hystrix/timeout/{id}")
    public String bookInfo_Timeout(@PathVariable("id") Integer id) {
        String result = bookService.bookInfo_Timeout(id);
        log.info("端口号:" + serverPort + "result:" + result);
        return result + ",端口号:" + serverPort;
    }
}
  1. 主启动类上开启熔断功能
@SpringBootApplication
@EnableEurekaClient
//@EnableCircuitBreaker 开启熔断器功能 新版本中已经弃用,可以使用其子类作为注解使用@EnableHystrix
@EnableHystrix
public class SpringCloudProviderHystrix9007Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudProviderHystrix9007Application.class, args);
    }

}
  1. 请求测试

Spring Cloud Hystrix - 图2

  • 当请求超时服务时响应如下,服务被降级到指定的方法上进行返回

Spring Cloud Hystrix - 图3

客户端服务降级

通常情况下,我们会在客户端进行服务降级,当客户端调用的服务端的服务不可用时,客户端直接进行服务降级处理,避免其线程被长时间、不必要地占用。流程如下:
  1. 新建Hystrix消费者模块spring-cloud-consumer-hystrix-9008pom.xml添加所需核心依赖
<!--引入 Eureka Client 的依赖,将服务注册到 Eureka Server-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--hystrix 依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.8.RELEASE</version>
</dependency>
<!--添加 OpenFeign 依赖。要借助openfeign实现远程服务调用-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. <font style="color:rgb(68, 68, 68);">application.yml </font>中添加以下配置,开启客户端的 <font style="color:rgb(68, 68, 68);">Hystrix </font>功能
#开启客户端 hystrix
feign:
  hystrix:
    enabled: true
  1. 创建一个名为 BookService 的服务绑定接口,与 spring-cloud-consumer-hystrix-9007 中提供的服务接口进行绑定
@Component
@FeignClient(value = "SPRING-CLOUD-PROVIDER-HYSTRIX-9007")
public interface BookService {

    //hystrix 熔断器正常访问案例
    @RequestMapping(value = "/book/hystrix/ok/{id}")
    public String bookInfo_Ok(@PathVariable("id")Integer id);

    //hystrix 熔断器超时案例
    @RequestMapping(value = "/book/hystrix/timeout/{id}")
    public String bookInfo_Timeout(@PathVariable("id")Integer id);
}

注意:参数里的 @PathVariable(“id”)一定要写不然请求会404

  1. 新建Controller调用测试
@RestController
@Slf4j
public class BookController {
    @Autowired
    private BookService bookService;

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

    @RequestMapping(value = "/book/hystrix/ok/{id}")
    public String bookInfo_Ok(@PathVariable("id") Integer id) {
        String result = bookService.bookInfo_Ok(id);
        log.info("端口号:" + serverPort + "result:" + result);
        return result + ",端口号:" + serverPort;
    }

    // Hystrix 服务超时降级
    @RequestMapping(value = "/book/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "book_TimeoutHandler",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
    }) //fallbackMethod:为该请求指定专属的回退方法 HystrixProperty:超时时间
    public String bookInfo_Timeout(@PathVariable("id") Integer id) {
        String result = bookService.bookInfo_Timeout(id);
        log.info("端口号:" + serverPort + "result:" + result);
        return result + ",端口号:" + serverPort;
    }

    // bookInfo_Timeout方法的 专用 fallback 方法
    public String book_TimeoutHandler(@PathVariable("id") Integer id) {
        log.info("bookInfo_Timeout 出错,服务已被降级*^____^*");
        return "服务端系统异常,请稍后再试!(客户端 bookInfo_Timeout 专属的回退方法触发*^____^*)";
    }
}
  1. 启动类上,使用 @EnableHystrix 注解开启客户端 Hystrix 功能
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
public class SpringCloudConsumerHystrix9008Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudConsumerHystrix9008Application.class, args);
    }

}
  1. 测试

启动注册中心,服务提供者(spring-cloud-provider-hystrix-9007),服务消费者(spring-cloud-provider-hystrix-9008)进行测试。

由于服务消费者我们设置了超时时间为3s,而服提供者的方法中我们休眠了6s,所以客户端调用http://127.0.0.1:9008/book/hystrix/timeout/1就会自动降级,调用我们的降级方法 book_TimeoutHandler,结果如下:

Spring Cloud Hystrix - 图4

全局降级方法

通过上面的方式实现服务降级时,需要针对所有业务方法都配置降级方法,这极有可能会造成代码的急剧膨胀。为了解决该问题,我们还可以为所有业务方法指定一个全局的回退方法,具体步骤如下。
  1. 在服务消费端 spring-cloud-consumer-hystrix-9008配置 BookController类上标注 <font style="color:rgb(68, 68, 68);">@DefaultProperties </font>注解,并通过其 <font style="color:rgb(68, 68, 68);">defaultFallback </font>属性指定一个全局的降级方法,和配置超时时间@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000"
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "book_Global_FallbackMethod",commandProperties = {
        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
}) //全局的服务降级方法
public class BookController {
    ……
}
  1. 在当前类中创建全局方法book_Global_FallbackMethod用作降级方法
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "book_Global_FallbackMethod",commandProperties = {
        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
}) //全局的服务降级方法
public class BookController {
    //……

    /**
     * 全局的 fallback 方法,回退方法必须和 hystrix 的执行方法在相同类中,否则无法生效
     * @DefaultProperties(defaultFallback = "book_Global_FallbackMethod") 类上注解,请求方法上使用 @HystrixCommand 注解
     */
    public String book_Global_FallbackMethod() {
        return "C语言中文网提醒您,运行出错或服务端系统繁忙,请稍后再试!(客户端全局回退方法触发,)";
    }
}
  1. 然后在所有业务方法上都标注 <font style="color:rgb(68, 68, 68);">@HystrixCommand</font> 注解即可实现全局方法。
@RequestMapping(value = "/book/hystrix/timeout/{id}")
@HystrixCommand //使用全局降级方法
public String bookInfo_Timeout(@PathVariable("id") Integer id) {
    String result = bookService.bookInfo_Timeout(id);
    log.info("端口号:" + serverPort + "result:" + result);
    return result + ",端口号:" + serverPort;
}

注意:全局降级方法的优先级较低,只有业务方法没有指定其降级方法时,服务降级时才会触发全局回退方法。若业务方法指定它自己的回退方法,那么在服务降级时,就只会直接触发它自己的回退方法,而非全局回退方法。

Spring Cloud Hystrix - 图5

解耦降级实现

不管是业务方法上指定的降级方法还是全局降级方法,它们都必须和业务方法在同一个类中才能生效,业务逻辑与降级逻辑耦合度极高。下面我们学习下如何把他们解耦,步骤如下:
  1. spring-cloud-consumer-hystrix-9008下为BookService创建异常扑捉实现类 BookHystrixFallBackServiceImpl统一为BookService中的方法提供服务降级处理
/**
 * Hystrix 服务降级 解耦回退逻辑
 */
@Component
public class BookHystrixFallBackServiceImpl implements BookService {

    @Override
    public String bookInfo_Ok(Integer id) {
        return "bookInfo_Ok解耦方法调用成功*^____^*";
    }

    @Override
    public String bookInfo_Timeout(Integer id) {
        return "bookInfo_Timeout解耦方法调用成功*^____^*";
    }
}
注意:该类必须以组件的形式添加 Spring 容器中才能生效,最常用的方式就是在类上标注 @Component 注解。
  1. 在服务绑定接口BookService上的@FeignClient注解添加fallback属性进行绑定
@Component
@FeignClient(value = "SPRING-CLOUD-PROVIDER-HYSTRIX-9007",fallback = BookHystrixFallBackServiceImpl.class)
public interface BookService {

    //hystrix 熔断器正常访问案例
    @RequestMapping(value = "/book/hystrix/ok/{id}")
    public String bookInfo_Ok(@PathVariable("id")Integer id);

    //hystrix 熔断器超时案例
    @RequestMapping(value = "/book/hystrix/timeout/{id}")
    public String bookInfo_Timeout(@PathVariable("id")Integer id);
}
  1. application.yaml配置开启Hystrix

这是由于feign中没有开启hystrix,于是我们按照网上的教程添加配置进行开启

#开启客户端 hystrix
feign:
  hystrix:
    enabled: true

结果发现没有任何用处,这是因为feign.hystrix.enabledspringcloud2020.0.1已经找不到了,对应新的控制装配的是

#开启客户端 hystrix
feign:
  circuitbreaker:
    enabled: true

根据自己使用的版本选择不同的配置。

  1. 启动服务注册中心(spring-cloud-eureka-server-9001)和服务消费者(spring-cloud-consumer-hystrix-9008),服务提供者我们这里不启动,模拟服务提供者宕机异常,进行访问

Spring Cloud Hystrix - 图6

Hystrix 服务熔断

熔断机制是为了应对雪崩效应而出现的一种微服务链路保护机制。 当微服务系统中的某个微服务不可用或响应时间太长时,为了保护系统的整体可用性,熔断器会暂时切断请求对该服务的调用,并快速返回一个友好的错误响应。这种熔断状态不是永久的,在经历了一定的时间后,熔断器会再次检测该微服务是否恢复正常,若服务恢复正常则恢复其调用链路。

熔断状态

在熔断机制中涉及了三种熔断状态:
  • 熔断关闭状态(Closed):当服务访问正常时,熔断器处于关闭状态,服务调用方可以正常地对服务进行调用。
  • 熔断开启状态(Open):默认情况下,在固定时间内接口调用出错比率达到一个阈值(例如 50%),熔断器会进入熔断开启状态。进入熔断状态后,后续对该服务的调用都会被切断,熔断器会执行本地的降级(FallBack)方法。
  • 半熔断状态(Half-Open): 在熔断开启一段时间之后,熔断器会进入半熔断状态。在半熔断状态下,熔断器会尝试恢复服务调用方对服务的调用,允许部分请求调用该服务,并监控其调用成功率。如果成功率达到预期,则说明服务已恢复正常,熔断器进入关闭状态;如果成功率仍旧很低,则重新进入熔断开启状态。

三张熔断之间的转换关系

熔断器流转概念图参考自官:https://martinfowler.com/bliki/CircuitBreaker.html

画板

Hystrix 实现服务熔断的步骤如下:
  1. 当服务的调用出错率达到或超过 Hystix 规定的比率(默认为 50%)后,熔断器进入熔断开启状态。
  2. 熔断器进入熔断开启状态后,Hystrix 会启动一个休眠时间窗,在这个时间窗内,该服务的降级逻辑会临时充当业务主逻辑,而原来的业务主逻辑不可用。
  3. 当有请求再次调用该服务时,会直接调用降级逻辑快速地返回失败响应,以避免系统雪崩。
  4. 当休眠时间窗到期后,Hystrix 会进入半熔断转态,允许部分请求对服务原来的主业务逻辑进行调用,并监控其调用成功率。
  5. 如果调用成功率达到预期,则说明服务已恢复正常,Hystrix 进入熔断关闭状态,服务原来的主业务逻辑恢复;否则 Hystrix 重新进入熔断开启状态,休眠时间窗口重新计时,继续重复第 2 到第 5 步。

使用步骤

  1. spring-cloud-provider-hystrix-9007服务提供者模块基础之上做修改,在 BookService 添加一个服务熔断方法bookCircuitBreaker
public interface BookService {

    //hystrix 熔断器正常访问案例
    public String bookInfo_Ok(Integer id);

    //hystrix 熔断器超时案例
    public String bookInfo_Timeout(Integer id);

    // Hystrix 熔断机制案例
    public String bookCircuitBreaker(Integer id);
}
  1. 在实现类中添加如下方法
@Service
public class BookServiceImpl implements BookService {

    /**
     * 正常访问方法
     */
    @Override
    public String bookInfo_Ok(Integer id) {
        return "线程池【" + Thread.currentThread().getName() + "】 bookInfo_Ok,id: 【" + id + "】";
    }

    /**
     * 一旦该方法失败并抛出了异常信息后,会自动调用  @HystrixCommand 注解标注的 fallbackMethod 指定的方法
     */
    @HystrixCommand(fallbackMethod = "book_TimeoutHandler",
            commandProperties =//规定 5 秒钟以内就不报错,正常运行,超过 5 秒就报错,调用指定的方法
                    {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")})
    @Override
    public String bookInfo_Timeout(Integer id) {
        int outTime = 4;
        try {
            TimeUnit.SECONDS.sleep(outTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池:【" + Thread.currentThread().getName() + "】  bookInfo_Timeout,id: 【" + id + "】耗时: " + outTime;
    }

     /**
     * 熔断调用的方法
     */
    public String book_TimeoutHandler(Integer id) {
        return "系统异常请稍后再试!线程池:【" + Thread.currentThread().getName() + "】bookInfo_Timeout,id:【" + id + "】";
    }


    //Hystrix 熔断案例
    @HystrixCommand(fallbackMethod = "book_CircuitBreaker_fallback", commandProperties = {
            //以下参数在 HystrixCommandProperties 类中有默认配置
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //是否开启熔断器
            @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "5000"), //统计时间窗
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), //统计时间窗内请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //休眠时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), //在统计时间窗口期以内,请求失败率达到 60% 时进入熔断状态
    })
    @Override
    public String bookCircuitBreaker(Integer id) {
        if (id < 0) {
            //当传入的 id 为负数时,抛出异常,调用降级方法
            throw new RuntimeException("deptCircuitBreaker数据处理异常,id不能是负数!*^____^*");
        }
        String serialNum = IdUtil.simpleUUID();
        return Thread.currentThread().getName() + "调用成功,流水号为:" + serialNum;
    }

    /**
     * bookCircuitBreaker熔断方法
     */
    public String book_CircuitBreaker_fallback(Integer id) {
        return "系统异常请稍后再试!id:【" + id + "】不能为负数*^____^*";
    }
}
  • timeInMilliseconds(统计时间窗)
  • requestVolumeThreshold(请求总数阀值):在快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。
  • sleepWindowInMilliseconds :休眠时间窗,熔断开启状态持续一段时间后,熔断器会自动进入半熔断状态,这段时间就被称为休眠窗口期,默认为最近的10秒。
  • errorThresholdPercentage(错误百分比阀值):当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阀值情况下,这时候就会将断路器打开。
  1. 添加Controller对外提供服务方法
@RestController
@Slf4j
public class BookController {

    @Autowired
    private BookService bookService;

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

    @RequestMapping(value = "/book/hystrix/ok/{id}")
    public String bookInfo_Ok(@PathVariable("id") Integer id) {
        String result = bookService.bookInfo_Ok(id);
        log.info("端口号:" + serverPort + "result:" + result);
        return result + ",端口号:" + serverPort;
    }

    // Hystrix 服务超时降级
    @RequestMapping(value = "/book/hystrix/timeout/{id}")
    public String bookInfo_Timeout(@PathVariable("id") Integer id) {
        String result = bookService.bookInfo_Timeout(id);
        log.info("端口号:" + serverPort + "result:" + result);
        return result + ",端口号:" + serverPort;
    }

    // Hystrix 服务熔断
    @RequestMapping(value = "/book/hystrix/circuit/{id}")
    public String deptCircuitBreaker(@PathVariable("id") Integer id) {
        String result = bookService.bookCircuitBreaker(id);
        log.info("端口号:" + serverPort + "result:" + result);
        return result;
    }
}
  1. 测试

Hystrix图形化Dashboard搭建

Hystrix 还提供了准实时的调用监控(Hystrix Dashboard)功能,Hystrix 会持续地记录所有通过 Hystrix 发起的请求的执行信息,并以统计报表的形式展示给用户,包括每秒执行请求的数量、成功请求的数量和失败请求的数量等。

我们学习下使用步骤。

  1. 单独创建 Dashboard 模块spring-cloud-consumer-hystrix-dashboard-9009,引入核心依赖
<!--hystrix 依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.8.RELEASE</version>
</dependency>
<!--hystrix-dashboard 监控的依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    <version>2.2.8.RELEASE</version>
</dependency>
<!-- Spring Boot 监控模块-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  1. 修改 application.yaml 配置文件
server:
  port: 9009

spring:
  application:
    name: spring-cloud-consumer-hystrix-dashboard-9009

hystrix:
  dashboard:
    proxy-stream-allow-list: "127.0.0.1" #根据自己访问地址配置即可
  1. 主启动类上添加 <font style="color:rgb(68, 68, 68);">@EnableHystrixDashboard </font>注解,开启 <font style="color:rgb(68, 68, 68);">Hystrix</font>监控功能,代码如下
s@SpringBootApplication
@EnableHystrixDashboard
public class SpringCloudConsumerHystrixDashboard9009Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudConsumerHystrixDashboard9009Application.class, args);
    }

}
  1. 在要被监控的模块里spring-cloud-provider-hystrix-9007添加配置类
@Configuration
public class HystrixDashboardConfig {

    /**
     *此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
     *ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
     *只要在自己的项目里配置上下面的servlet就可以了
     *否则,Unable to connect to Command Metric Stream 404
     */
    @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;
    }
}
  1. 启动 spring-cloud-consumer-hystrix-dashboard-9009浏览器访问http://127.0.0.1:9009/hystrix,结果如下图

Spring Cloud Hystrix - 图8

  1. 点击下方的 Monitor Stream 按钮,跳转到 Hystrix 对 micro-service-cloud-provider-dept-hystrix-8004 的监控页面,如下图。

Spring Cloud Hystrix - 图9

看到如下界面

Spring Cloud Hystrix - 图10

  1. 使用浏览器多次访问http://127.0.0.1:9007/book/hystrix/circuit/1http://127.0.0.1:9007/book/hystrix/circuit/-1,查看 Hystrix 监控页面,如下图

Spring Cloud Hystrix - 图11

:::info 监测界面认识

这个图可以简单的描述为 7色,1圈,1线

  • 7色:就是每种数值的颜色不一样,代表不同的程度

Spring Cloud Hystrix - 图12

  • 1圈:实心圆,共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。
    • 该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,就可以在大量的实例中快速的发现故障实例和高压力实例。
  • 1线:曲线,用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。

:::