Netflix Hystrix 降级方法使用

微服务中使用 Feign 实现服务间通信,Hystrix 提供服务间容错。本文主要讲hystrix中的 超时,熔断 ,隔离策略,适合对Hystrix 功能有基本了解的读者。

1 准备工作

三个服务: 服务提供者provider,服务消费者consumer,注册中心

provider 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>

provider 配置文件

server.port=9091
spring.application.name=provider-service
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:9090/eureka/

consumer 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

consumer 配置

server.port=9092
spring.application.name=consumer-service
eureka.client.serviceUrl.defaultZone=http://132.232.40.60:9090/eureka/
# 开启hystrix
feign.hystrix.enabled=true

consumer 定义服务端的Feign接口

@FeignClient(value = "provider-service", fallbackFactory = OrderClientFallback.class)
public interface OrderClient {
    @GetMapping("/hystrix/timeOut")
    String getOrder();
    
    @GetMapping("/hystrix/strategy/thread")
    String strategyThread();

    @GetMapping("/hystrix/strategy/semaphore")
    String strategySemaphore();

    @GetMapping("/hystrix/circuitBreaker")
    String circuitBreake(@RequestParam("n") int n, @RequestParam("m") int m);
}

OrderClientFallback:

@Component
public class OrderClientFallback implements FallbackFactory<OrderClient>{
    @Override
    public  OrderClient create(Throwable cause) {
       return new OrderClient(){
            @Override
            public String getOrder() {
                return "被降降级了";
            }
            
           @Override
           public String strategyThread() {
               return "被降降级了";
           }
           @Override
           public String circuitBreake(int n,int m) {
               if (cause != null) {
                   cause.printStackTrace();
               }
               return "被降降级了";
           }
           @Override
           public String strategySemaphore() {
               if (cause != null) {
                   cause.printStackTrace();
               }
               return "被降降级了";
           }
       };
    }
}

注册中心 省略

2 实战

在Hystrix 中配置文件主要放在 HystrixCommandProperties.java 文件中。

1) 超时: 默认开启,超时时间默认设置为1秒。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cLRXQXOJ-1615456342143)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1614845569106.png)]

服务端设置超时两秒

@GetMapping("/hystrix/timeOut")
public String timeOut() throws InterruptedException {
   Thread.sleep(2000);
    return "ok";
}

请求测试:超时后服务被降级,走了Fallback方法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-65Jl7uXn-1615456342146)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1614846267088.png)]

修改consumer配置或者设置实例属性:超时时间设置为5秒,再次请求。

  1. 默认属性配置
##默认属性
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
##实例属性
## hystrix.command.HystrixCommandkey.execution.isolation.thread.timeoutInMilliseconds=500
  1. 实例属性配置

    @GetMapping("/test/timeOut")
    @HystrixCommand(commandProperties = {
    @HystrixProperty(name ="execution.isolation.thread.timeoutInMilliseconds",value = "5000")
    })
    public String timeOut(){
        String str = orderClient.timeOut();
        return str;
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pa8agnHI-1615456342148)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1614849949077.png)]

2)断路器:默认开启,采用滑动窗口算法,窗口默认为10个,每个存储时间为1秒。请求阈值默认20,失败率超过50%开启断路器,断路器默认休眠5s。

解释:在10秒内必须有20个请求通过,失败率在50% 会触发开关,开关打开后在5秒被不会再请求服务端,5s后尝试请求判断是否成功,失败继续断开,成功关闭断路器。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NvyZilMt-1615456342151)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1614851042701.png)]

利用jmerer和伪代码测试断路器。

服务端伪代码 当传入参数n>15 m<=60 程序会报错(制造错误率)

@GetMapping("/hystrix/circuitBreaker")
public String circuitBreaker(int n,int m){
    if(n>15&&m<=60){
        int a=0;
        int b=10;
        int c=b/a;
    }
    return n+"";
}

jemter 设置30 秒通过100个线程。超过默认10秒20线程,当失败率达到50% 短路器打开。从图中可以看出断路器开启了5s。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nYKHm1a7-1615456342153)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1614853363572.png)]

修改断路器默认配合属性:

  1. 默认默认属性修改
# 请求阈值
hystrix.command.default.circuitBreaker.requestVolumeThreshold=10
# 失败率
hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
## 断路器打开后休眠时间,默认5秒
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=2000
  1. 实例属性修改

    @HystrixCommand(commandProperties = {
            @HystrixProperty(name ="circuitBreaker.requestVolumeThreshold",value = "10"),
            @HystrixProperty(name ="circuitBreaker.errorThresholdPercentage",value = "50"),
            @HystrixProperty(name ="circuitBreaker.sleepWindowInMilliseconds",value = "2000"),
    })
    
3) 隔离策略:线程池+信号量
  • 线程池(Threadpoll)

    默认使用的是线程池隔离模式。

    线程池默认配置属性: HystrixThreadPoolProperties.java

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HabevZdo-1615456342154)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1615448069394.png)]

    • 属性修改:

      • 1 修改默认属性

        #默认属性
        hystrix.command.default.execution.isolation.strategy=THREAD
        ##使用 maximumSize 必须开启allowMaximumSizeToDivergeFromCoreSize=true
        hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize=true
        hystrix.threadpool.default.coreSize=2
        hystrix.threadpool.default.maximumSize=2
        hystrix.threadpool.default.keepAliveTimeMinutes=2
        hystrix.threadpool.default.maxQueueSize=10
        hystrix.threadpool.default.queueSizeRejectionThreshold=2
        #实例属性 HystrixtTreadpoolKey 默认类名
        hystrix.threadpool.HystrixtTreadpoolKey.coreSize=2
        

        使用maximumSize必须开启allowMaximumSizeToDivergeFromCoreSize

        public Integer actualMaximumSize() {
            final int coreSize = coreSize().get();
            final int maximumSize = maximumSize().get();
            if (getAllowMaximumSizeToDivergeFromCoreSize().get()) {
                if (coreSize > maximumSize) {
                    return coreSize;
                } else {
                    return maximumSize;
                }
            } else {
                return coreSize;
            }
        }
        
        • 2 修改实例属性:

          • 注解方式:
          @HystrixCommand(
                  groupKey = "UserController",//默认类名
                  commandKey = "strategyThread",//默认方法名
          threadPoolKey = "provider-service",//服务提供者名
          threadPoolProperties = {
                  @HystrixProperty(name = "coreSize",value = "2"),
                  @HystrixProperty(name = "maxQueueSize",value = "10"),
                  @HystrixProperty(name = "keepAliveTimeMinutes",value = "2"),
                  @HystrixProperty(name = "queueSizeRejectionThreshold",value = "10")
          
          },fallbackMethod = "fallback")
          

          注意:注解方式使用设置不了 maximumSize,(HystrixPropertiesManager.java)中没有定义

          maximumSize 属性。

        • 测试结果。

          线程池触发拒绝策略抛出异常,触发fallback,当失败率满足熔断器设定的规则,会打开断路器。

  • 信号量 (SEMAPHORE)

    信号量默认配置:默认允许最大请求数为10

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wMQGAk9O-1615456342155)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1615453481891.png)]

    • 默认属性修改:
    #  信号量 默认属性
    hystrix.command.default.execution.isolation.strategy=SEMAPHORE
    hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=5
    # 实例属性 HystrixtCommandKey=提供服务feginClient的服务名#方法名(参数类型)   默认是方法名
    # 例如 OrderClient#strategySemaphore(int)
    hystrix.command.HystrixtCommandKey.execution.isolation.semaphore.maxConcurrentRequests=5
    
    
    • 注解方式:fallback 方法和实例方法在同类并且参数必须一致。
    @HystrixCommand(commandProperties={
            @HystrixProperty(name = "execution.isolation.strategy",value = "SEMAPHORE"),
            @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests",value = "5")
    },fallbackMethod = "fallback")
    
    • 测试结果

      当线程超过设定值,触发fallback ,满足熔断条件,开启断路器。

3 总结:

hystrix 降级策略 分为三种:

  1. 超时降级
    • 默认开启 (timeOut=1s)
  2. 熔断降级(特殊的降级方式)
    • 默认开启 (10秒内20个请求 失败率在50%)
  3. 隔离策略降级
    • 线程池隔离 默认使用策略
    • 信号量隔离
上一篇:【原创】JAVA8之妙用Optional解决NPE问题


下一篇:Eclipse plugin web site 发布和版本更新