3、Hystrix 服务降级

Hystrix使用fallback机制很简单,继承HystrixCommand只需重写getFallback(),继承HystrixObservableCommand只需重写resumeWithFallback(),比如上篇文章的HelloWorldHystrixCommand加上下面代码片段:

 @Override
protected String getFallback() {
    return "fallback: " + name;
}

fallback实际流程是当run()/construct()被触发执行时或执行中发生错误时,将转向执行getFallback()/resumeWithFallback()

结合下图,4种情况(出现异常,超时,熔断,线程池已满)将触发fallback:

run()方法中出现异常

(非HystrixBadRequestException异常)或者出现超时()触发fallback()

 public class HystrixFallbackNomal extends HystrixCommand<String>{

  private final String name;

   public HystrixFallbackNomal(String name) {
    super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
    this.name = name;
  }

  @Override
  public String run() throws Exception {
    /*---------------会触发fallback的case-------------------*/
        // 无限循环,实际上属于超时
    /*  int j = 0;
        while (true) {
            j++;
        }*/
    Thread.sleep(1000);

        // 除零异常
        // int i = 1/0;

        // 主动抛出异常
//      throw new HystrixTimeoutException();
//      throw new RuntimeException("this command will trigger fallback");
//      throw new Exception("this command will trigger fallback");
//      throw new HystrixRuntimeException(FailureType.BAD_REQUEST_EXCEPTION, commandClass, message, cause, fallbackException);

        /*---------------不会触发fallback的case-------------------*/
        // 被捕获的异常不会触发fallback
//      try {
//          throw new RuntimeException("this command never trigger fallback");
//      } catch(Exception e) {
//          e.printStackTrace();
//      }

        // HystrixBadRequestException异常由非法参数或非系统错误引起,不会触发fallback,也不会被计入熔断器
        //throw new HystrixBadRequestException("HystrixBadRequestException is never trigger fallback");

     //return name;
    }

    @Override
    protected String getFallback() {
      return "fallback: " + name;
    }
  }
}

熔断触发fallback()

 /**
 * 熔断机制相当于电路的跳闸功能,例如:我们可以配置熔断策略为当请求错误比例在10s内>50%时,该服务将进入熔断状态,后续请求都会进入fallback
 * CircuitBreakerRequestVolumeThreshold设置为3,意味着10s内请求超过3次就触发熔断器(10s这个时间暂时不可配置)
 * run()中无限循环使命令超时进入fallback,10s内请求超过3次,将被熔断,进入降级,即不进入run()而直接进入fallback
 * 如果未熔断,但是threadpool被打满,仍然会降级,即不进入run()而直接进入fallback
 */
public class HystrixFallbackCircuitBreaker extends HystrixCommand<String>{
    private final String name;

    public HystrixFallbackCircuitBreaker(String name) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("CircuitBreakerTestGroup"))  
                .andCommandKey(HystrixCommandKey.Factory.asKey("CircuitBreakerTestKey"))
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("CircuitBreakerTest"))
                .andThreadPoolPropertiesDefaults(   // 配置线程池
                        HystrixThreadPoolProperties.Setter()
                        .withCoreSize(200)  // 配置线程池里的线程数,设置足够多线程,以防未熔断却打满threadpool
                )
                .andCommandPropertiesDefaults(  // 配置熔断器
                        HystrixCommandProperties.Setter()
                        .withCircuitBreakerEnabled(true)
                        .withCircuitBreakerRequestVolumeThreshold(3)
                        .withCircuitBreakerErrorThresholdPercentage(80)
//                          .withCircuitBreakerForceOpen(true)  // 置为true时,所有请求都将被拒绝,直接到fallback
//                          .withCircuitBreakerForceClosed(true)    // 置为true时,将忽略错误
//                          .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)   // 信号量隔离
//                          .withExecutionTimeoutInMilliseconds(5000)
                )
        );
        this.name = name;
    }

    @Override
    protected String run() throws Exception {
        System.out.println("running run():" + name);
        int num = Integer.valueOf(name);
        if(num < 10) {   // 直接返回
          return name;
        } else {    // 无限循环模拟超时
          int j = 0;
          while (true) {
          j++;
          }
        }
//  return name;
    }

    @Override
    protected String getFallback() {
        return "CircuitBreaker fallback: " + name;
    }
}
     @Test
       public void testFallbackCricuitBreaker() throws IOException {
        for(int i = 0; i < 50; i++) {
         try {
            System.out.println("===========" + new HystrixFallbackCircuitBreaker(String.valueOf(i)).execute());
         } catch(Exception e) {
               System.out.println("run()抛出HystrixBadRequestException时,被捕获到这里" + e.getCause());
         }
        }

        System.out.println("------开始打印现有线程---------");
        Map<Thread, StackTraceElement[]> map=Thread.getAllStackTraces();
        for (Thread thread : map.keySet()) {
      System.out.println(thread.getName());
    }
        System.out.println("thread num: " + map.size());

        System.in.read();
       }               

线程池已满,触发fallback()

 public class HystrixThreadPoolFallback extends HystrixCommand<String>{

  private final String name;

    public HystrixThreadPoolFallback(String name) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ThreadPoolTestGroup"))  
                .andCommandKey(HystrixCommandKey.Factory.asKey("testCommandKey"))
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("ThreadPoolTest"))
                .andCommandPropertiesDefaults(
                    HystrixCommandProperties.Setter()
                        .withExecutionTimeoutInMilliseconds(5000)
                )
                .andThreadPoolPropertiesDefaults(
                    HystrixThreadPoolProperties.Setter()
                        .withCoreSize(3)    // 配置线程池里的线程数
                )
        );
        this.name = name;
    }

  @Override
    protected String run() throws Exception {
        System.out.println(name);
    TimeUnit.MILLISECONDS.sleep(2000);
    return name;
    }

    @Override
    protected String getFallback() {
        return "fallback: " + name;
    }
}
  @Test
public void testThreadPool() throws IOException {
    for(int i = 0; i < 10; i++) {
      try {
        Future<String> future = new HystrixThreadPoolFallback("Hlx"+i).queue();
      } catch(Exception e) {
        System.out.println("run()抛出HystrixBadRequestException时,被捕获到这里" + e.getCause());
      }
    }
    for(int i = 0; i < 20; i++) {
      try {
        System.out.println("===========" + new HystrixThreadPoolFallback("Hlx"+i).execute());
      } catch(Exception e) {
        System.out.println("run()抛出HystrixBadRequestException时,被捕获到这里" + e.getCause());
      }
    }
    try {
      TimeUnit.MILLISECONDS.sleep(2000);
    }catch(Exception e) {}
    System.out.println("------开始打印现有线程---------");
    Map<Thread, StackTraceElement[]> map=Thread.getAllStackTraces();
    for (Thread thread : map.keySet()) {
        System.out.println(thread.getName());
    }
    System.out.println(map);
    System.out.println("thread num: " + map.size());

    System.in.read();
}