虽然已进入维护阶段但是一些理念还是可以了解一下的。

一、Hystrix 是什么?

在分布式环境中,许多服务依赖中的一些服务发生失败是不可避免的。Hystrix是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点、停止跨服务的级联故障以及提供回退选项来实现这一点,所有这些都可以提高系统的整体弹性。也就是说Hystrix是一种类似于熔断保险丝的开关装置。在消费者端安装一个Hystrix熔断器。当Hystrix监控到某个服务发生故障后熔断器就会开启,将此服务访问链路断开。不过Hystrix并不会将该服务的消费者阻塞,或向消费者抛出异常,而是向消费者返回一个符合预期的备选响应(FallBack)。通过Hystrix的熔断与降级功能,避免了服务雪崩的发生,同时也考虑到了用户体验,故Hystrix是系统的一种防御机制。

二、Hystrix 能帮我们做什么?

2.1、服务降级

服务降级指的是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。

2.2、服务熔断

所谓的服务熔断指的是某个服务故障或异常一起类似显示世界中的“保险丝”当某个异常条件被触发就直接熔断整个服务,而不是一直等到此服务超时。

2.3、服务限流

在 Sentinel 中再详细展开说明。

三、如何在业务中使用 Hystrix?

3.1、使用Hystirx 为服务端进行服务降级

在服务端进行服务降级的演示

步骤一:在主启功类上添加注解@EnableCircuitBreaker

在SpringBoot的主启动类上添加注解以开启 Hystrix 相关特性,代码如下。

  1. @SpringBootApplication
  2. @EnableCircuitBreaker
  3. public class CloudProviderHystrixPayment8001Application {
  4. public static void main(String[] args) {
  5. SpringApplication.run(CloudProviderHystrixPayment8001Application.class, args);
  6. }
  7. }

步骤二:在业务代码中使用@HystrixCommand为业务方法指定降级方法

通过例子来说明每个注解的作用,代码如下。

  • 使用@HystrixCommand表示该方法受到 Hystrix 的保护

    • 属性fallbackMethod用于指定当前方法满足服务降价的条件时执行的方法名。
    • 属性commandProperties用于指定除方法报错以外的服务降级条件。 ```java @Service public class PaymentService { /**

      • 超时访问,设置自身调用超时的峰值,峰值内正常运行,超过了峰值需要服务降级 自动调用fallbackMethod 指定的方法
      • 超时异常或者运行异常 都会进行服务降级 *
      • @param id
      • @return */ @HystrixCommand(fallbackMethod = “paymentInfoTimeOutHandler”, commandProperties = { //用于指定方法执行超时时间 @HystrixProperty(name = “execution.isolation.thread.timeoutInMilliseconds”, value = “5000”) }) public String paymentInfoTimeOut(Integer id) { int age = 10/0; return “线程池: “ + Thread.currentThread().getName() + “ paymentInfoTimeOut,id: “ + id + “\t”
        1. + "O(∩_∩)O哈哈~" + " 耗时(秒): " + second;
        }

      /**

      • paymentInfoTimeOut 方法失败后 自动调用此方法 实现服务降级 告知调用者 paymentInfoTimeOut 目前无法正常调用 *
      • @param id
      • @return */ public String paymentInfoTimeOutHandler(Integer id) { return “线程池: “ + Thread.currentThread().getName() + “ paymentInfoTimeOutHandler8001系统繁忙或者运行报错,请稍后再试,id: “ + id + “\t”+ “o(╥﹏╥)o”; } }
<a name="elMVa"></a>
### 3.2、使用Hystirx 为消费端进行服务降级
服务降级一般都是在消费端去做的,那么在使用 Open Feign 的情况下,下面我们一起来看一下 Hystrix 是如何配合 Open Feign实现服务降级的。
<a name="FPgpa"></a>
##### 步骤一:添加 Hystrix 依赖
在`pom.xml`文件中添加如下内容,引入 Hystrix 相关功能。
```xml
<!--hystrix-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

步骤二:在主启功类上添加注解@EnableHystrix

在主启动类添加注解以开启 Hystrix

@SpringBootApplication
@EnableFeignClients // 启动 feign
@EnableHystrix // 启动 hystrix
public class CloudConsumerFeignHystrixOrder80Application {

    public static void main(String[] args) {
        SpringApplication.run(CloudConsumerFeignHystrixOrder80Application.class, args);
        System.out.println("启动成功");

}

步骤三:修改 application.yaml 以开启 Hystrix

通过以下属性使得在 Open Feign 执行 RPC 调用时实现 Hystrix 的相关功能,其中就包括服务降级。

feign:
  hystrix:
    enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。

步骤四:在业务代码中使用服务降级

此处使用方式和在服务端进行服务降级一样,具体属性说明参考服务端服务降级相关内容。

@RestController
public class OrderHystrixController {

    @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) {
        //int age = 10/0;
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }


    /**
     * hystrix 服务降级方法
     *
     * @return
     */
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
        return "我是消费者80,对方支付系统繁忙请10秒种后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
    }

}

3.3、服务降级进一步优化

3.3.1、问题一:解决每个方法都需要配置一个 fallback 属性

为了应对该问题 Hystrix 提供了一种方案,使用@DefaultProperties合理的减少了代码量。

@RestController
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystrixController {

    @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) {
        //int age = 10/0;
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }

    @GetMapping("/consumer/payment/hystrix/global/{id}")
    @HystrixCommand
    public String paymentInfoGlobal(@PathVariable("id") Integer id) {
        int age = 10/0;
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }


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

    /**
     * hystrix 全局fallback方法
     * @return 
     */
    public String payment_Global_FallbackMethod() {
        return "Global异常处理信息,请稍后再试,/(ㄒoㄒ)/~~";
    }

}

通过使用@DefaultProperties注解,我们在使用@HystrixComman注解时不需要再具体配置相关属性也可以实现服务降级,从而减少代码量。

3.3.2、问题二:在消费端做服务降级,降级方法和业务方法掺杂在一起导致代码混乱

解决这个问题,首先我们定义一个类实现 Open Feign 调用的接口,然后使用注解指定服务降级的类,这样就可以把降级代码从业务代码中抽离出来。
步骤一:实现 OpenFeign 接口并定义降级逻辑

@Component
public class PaymentFallbackServiceImpl implements PaymentHystrixService {

    @Override
    public String paymentInfoOK(Integer id) {
        return "-----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o";
    }

    @Override
    public String paymentInfoTimeOut(Integer id) {
        return "-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o";
    }

}

步骤二:在 OpenFeign 接口上指定服务降级class
使用 fallback属性来定义服务降级类

    /**
     * Fallback class for the specified Feign client interface. The fallback class must
     * implement the interface annotated by this annotation and be a valid spring bean.
     * @return fallback class for the specified Feign client interface
     */
    Class<?> fallback() default void.class;
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackServiceImpl.class)
public interface PaymentHystrixService {
    @GetMapping("/payment/hystrix/ok/{id}")
    String paymentInfoOK(@PathVariable("id") Integer id);

    @GetMapping("/payment/hystrix/timeout/{id}")
    String paymentInfoTimeOut(@PathVariable("id") Integer id);
}

3.4、服务降级与全局异常捕获

通过以上的例子我们发现,其实Hystrix的服务降级和 SpringBoot 提供的@ControllerAdvice全局异常处理类似,这里补充说明一下,服务降级的优先等级高于全局异常处理。

3.5、服务熔断在代码中的实现

@HystrixCommandcommandProperties按照如下方式配置即可。
circuitBreaker.enabled属性用于配置是否开启服务熔断
circuitBreaker.requestVolumeThreshold属性用于配置请求参数
circuitBreaker.sleepWindowInMilliseconds用于配置时间窗口期,单位为ms
circuitBreaker.errorThresholdPercentage用于配置服务熔断条件,错误率达到百分之多少

    @HystrixCommand(fallbackMethod = "paymentCircuitBreakerFallback", 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(Integer id) {
        if (id < 0) {
            throw new RuntimeException("******id 不能负数");
        }
        String serialNumber = IdUtil.simpleUUID();
        return Thread.currentThread().getName() + "\t" + "调用成功,流水号: " + serialNumber;
    }