Spring Cloud Hystrix 配置

/ java / 没有评论 / 53浏览

Spring Cloud Hystrix

介绍

Spring Cloud Hystrix也是基于Netflix的开源框架Hystrix实现的, 主要在于通过控制访问远程系统、服务和第三方库的节点, 从而对延迟和故障提供更强大的容错能力. Hystrix具备服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等功能.

使用方式

需引入的依赖

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

启动类添加注解@EnableCircuitBreaker开启断路器 注: 还可以使用Spring Cloud中的@SpringCloudApplication注解修饰启动类, 该注解同时包含了@SpringBootApplication@EnableDiscoveryClient@EnableCircuitBreaker, 所以可以只引入一个注解.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}

使用@HystrixCommand注解指定失败回调, 当调用失败时则会执行失败回调返回error

@Service
public class HelloService {

    @Resource
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "helleFallback")
    public String helloService() {
        return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody();
    }

    public String helleFallback() {
        return "error";
    }

}

工作流程

下图为官方提供的工作流程图 github

2orcpu8d7ija8rtns88t20nlka

  1. 创建 HystrixCommand 或 HystrixObservableCommand 对象

    1. 首先构建一个HystrixCommand或者HystrixObservableCommand对象, 用来表示对依赖服务操作的请求, 同时传递需要的参数. 这两个Command分别针对不同的应用场景.
      1. HystrixCommand: 用在依赖的服务返回单子操作结果
      2. HystrixObservableCommand: 用在依赖的服务返回多个操作结果
  2. 命令执行 从图中可以看到一共存在4中命令执行方式, 其中HystrixCommand实现了下面两个执行方式 - execute(): 同步执行, 从依赖的服务返回一个单一的结果对象, 或是在发生错误的时候抛出异常. - queue(): 异步执行, 直接返回一个Future对象, 其中包含了服务执行结束时要返回的单一结果对象. R value = command.execute(); Future<R> fValue = command.queue(); HystrixObservableCommand实现了两外两种执行方式 - observe(): 返回Observable对象, 代表了操作的多个结果, 是一个Hot Observable(加了层 buffer 代理) - toObservable(): 返回Observable对象, 代表了操作的多个结果, 返回的是一个Cold Observable(observe方法的lazy版本) Observable<R> ohValue = command.observe(); Observable<R> ocValue = command.toObservable();

     `Observable`对象就是`RxJava`中的内容, 可以理解为 `事件源` 或者是`被观察者`, 对应的`Subscriber`对象, 可以理解为`订阅者`或者是`观察者`.
     - `Observable` 用来向订阅者`Subscriber`对象发布事件, `Subscriber`对象则在接收到事件后对其进行处理, 而这里的事件指的是对依赖服务的调用.
     -  一个`Observable`可以发出多个事件, 知道结束或者是发生异常
     -  `Observable` 对象每发出一个事件, 就会调用对应观察者`Subscruver`对象的`onNext()`方法
     - 每一个`Observable`的执行, 最后一定会通过调用`Subscriber.onCompleted()` 或者`Subscriber.onError()`来结束该事件的操作流
    

    HystrixCommandexecute()queue也都使用了RxJava来实现 - queue是通过toObservable()获得一个Cold Observable, toBlocking()Observable转换成BlockingObservable, 可以把数据以阻塞的方式发射出来, 再通过toFutureBlockingObservable转换为一个Future - execute 通过queue返回的异步对象Future<R>get()方法实现同步执行

  3. 执行操作指令时,Hystrix首先会检查缓存内是否有对应指令的结果,如果有的话,将缓存的结果直接以Observable对象的形式返回。如果没有对应的缓存,Hystrix会检查Circuit Breaker的状态。

  4. 如果Circuit Breaker的状态为开启状态,Hystrix将不会执行对应指令,而是直接进入失败处理状态(图中8 Fallback)。

  5. 如果Circuit Breaker的状态为关闭状态,Hystrix会继续进行线程池、任务队列、信号量的检查(图中5),确认是否有足够的资源执行操作指令。如果资源满,Hystrix同样将不会执行对应指令并且直接进入失败处理状态。

  6. 如果资源充足,Hystrix将会执行操作指令。操作指令的调用最终都会到这两个方法: HystrixCommand.run() HystrixObservableCommand.construct() 如果执行时间超出了设置的超时阈值, 处理线程会抛出TimeoutException(如果命令不在自身的线程中执行, 则会通过单独的计时线程抛出), 这种情况下, Hystrix会转接到fallback处理逻辑(第 8 步), 如果执行指令成功,Hystrix会进行一系列的数据记录,然后返回执行的结果。

  7. Hystrix会根据记录的数据来计算失败比率,一旦失败比率达到某一阈值将自动开启Circuit Breaker。

  8. 当命令执行失败, Hystrix会进入fallback尝试服务降级, 引起降级的情况有下面几种 1. 第四步, 命令处于熔断/短路状态, 断路器是打开的时候 2. 第五步, 命令的线程池、请求队列或者信号量被占满的时候 3. 第六步, HystrixObservableCommand.construct()或者HystrixCommand.run()抛出异常的时候 如果我们在Command中实现了HystrixCommand.getFallback()方法(或HystrixObservableCommand.resumeWithFallback()方法,Hystrix会返回对应方法的结果。如果没有实现这些方法的话,从底层看Hystrix将会返回一个空的Observable对象,并且可以通过onError来终止并处理错误。如果降级执行失败的时候,, Hystrix会根据不同的执行方法做出不同的处理 - execute方法将会抛出异常 - queue方法将会返回一个失败状态的Future对象 - observe()和toObservable()方法都会返回上述的Observable对象

  9. 返回成功响应

熔断器 Circuit Breaker

下图为官方提供的流程架构和统计 github

t1mor7ln64hv8ouh7v1f3696cs

每个熔断器默认维护10个bucket,每秒一个bucket,每个blucket记录成功,失败,超时,拒绝的状态, 默认错误超过50%且10秒内超过20个请求进行中断拦截.

隔离(Isolation)分析

Hystrix隔离方式采用线程/信号的方式,通过隔离限制依赖的并发量和阻塞扩散.

属性配置

HystrixCommand的配置方式有两种

  1. 通过继承, 使用Setter对象对请求命令的属性设置
        Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
            .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
            .withExecutionTimeoutInMilliseconds(500))
    
  2. 使用注解
        @HystrixCommand(fallbackMethod = "helleFallback", commandKey = "helloKey", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
        })
    

Hystirx配置优先级分为四种

  1. 全局默认值

        如果没有设置下面三个级别的属性, 这个属性就是默认值, 代码中定义.
    
  2. 全局配置属性

        配置文件中定义全局默认值, 在应用启动时或在与 Spring Cloud Config 和Spring Cloud Bus 实现的动态刷新配置功能配合下, 可以实现对 '全局默认值'的覆盖以及在运行期对 '全局默认值' 的动态调整
    
  3. 实例默认值

        通过代码为实例定义默认值, 覆盖默认的全局配置
    
  4. 实例配置属性

        通过配置文件为指定的实例进行属性配置, 覆盖前面三个默认值. 也可用 Spring Cloud Config 和 Spring Cloud Bus 实现的动态刷新配置功能实现对实例配置的动态调整
    

Command属性

  1. Command属性主要用来控制HystrixCommand命令的行为, 配置源码在HystrixCommandProperties
    //使用命令调用隔离方式,默认:采用线程隔离,ExecutionIsolationStrategy.THREAD
    private final HystrixProperty<ExecutionIsolationStrategy> executionIsolationStrategy; 
    //使用线程隔离时,调用超时时间,默认:1秒
    private final HystrixProperty<Integer> executionIsolationThreadTimeoutInMilliseconds; 
    //线程池的key,用于决定命令在哪个线程池执行
    private final HystrixProperty<String> executionIsolationThreadPoolKeyOverride; 
    //使用信号量隔离时,命令调用最大的并发数,默认:10
    private final HystrixProperty<Integer> executionIsolationSemaphoreMaxConcurrentRequests;
    //使用信号量隔离时,命令fallback(降级)调用最大的并发数,默认:10
    private final HystrixProperty<Integer> fallbackIsolationSemaphoreMaxConcurrentRequests; 
    //是否开启fallback降级策略 默认:true 
    private final HystrixProperty<Boolean> fallbackEnabled; 
    // 使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作.默认:true
    private final HystrixProperty<Boolean> executionIsolationThreadInterruptOnTimeout; 
    // 统计滚动的时间窗口,默认:5000毫秒circuitBreakerSleepWindowInMilliseconds
    private final HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds;
    // 统计窗口的Buckets的数量,默认:10个,每秒一个Buckets统计
    private final HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow
    //是否开启监控统计功能,默认:true
    private final HystrixProperty<Boolean> metricsRollingPercentileEnabled; 
    // 是否开启请求日志,默认:true
    private final HystrixProperty<Boolean> requestLogEnabled; 
    //是否开启请求缓存,默认:true
    private final HystrixProperty<Boolean> requestCacheEnabled; // Whether request caching is enabled.

例: execution 配置

execution 配置控制的时HystrixCommand.run()执行

属性级别默认值、配置方式、配置属性
全局默认值THREAD
全局配置属性hystrix.command.default.execution.isolation.strategy
实例默认值通过 HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)设置, 也可以通过 @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD") 注解设置
实例配置属性hystrix.command.HystrixCommandKey.execution.isolation.strategy
属性级别默认值、配置方式、配置属性
全局默认值1000毫秒
全局配置属性hystrix.command.default.execution.isolation.thread.timeoutinMilliseconds
实例默认值通过 HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)设置, 也可以通过 @HystrixProperty(name = "execution.isolation.thread.timeoutinMilliseconds", value = "500") 注解设置
实例配置属性hystrix.command.HystrixCommandKey.execution.isolation.thread.timeoutinMilliseconds
  1. 熔断器(Circuit Breaker)配置

Circuit Breaker配置源码在HystrixCommandProperties,构造Command时通过Setter进行配置,每种依赖使用一个Circuit Breaker

    // 熔断器在整个统计时间内是否开启的阀值,默认20秒。也就是10秒钟内至少请求20次,熔断器才发挥起作用  
    private final HystrixProperty<Integer> circuitBreakerRequestVolumeThreshold;   
    //熔断器默认工作时间,默认:5秒.熔断器中断请求5秒后会进入半打开状态,放部分流量过去重试  
    private final HystrixProperty<Integer> circuitBreakerSleepWindowInMilliseconds;   
    //是否启用熔断器,默认true. 启动  
    private final HystrixProperty<Boolean> circuitBreakerEnabled;   
    //默认:50%。当出错率超过50%后熔断器启动.  
    private final HystrixProperty<Integer> circuitBreakerErrorThresholdPercentage;  
    //是否强制开启熔断器阻断所有请求,默认:false,不开启  
    private final HystrixProperty<Boolean> circuitBreakerForceOpen;   
    //是否允许熔断器忽略错误,默认false, 不开启  
    private final HystrixProperty<Boolean> circuitBreakerForceClosed;
  1. 命令合并(Collapser)配置

Command配置源码在HystrixCollapserProperties,构造Collapser时通过Setter进行配置

    //请求合并是允许的最大请求数,默认: Integer.MAX_VALUE  
    private final HystrixProperty<Integer> maxRequestsInBatch;  
    //批处理过程中每个命令延迟的时间,默认:10毫秒  
    private final HystrixProperty<Integer> timerDelayInMilliseconds;  
    //批处理过程中是否开启请求缓存,默认:开启  
    private final HystrixProperty<Boolean> requestCacheEnabled;
  1. 线程池(ThreadPool)配置
    /** 
    配置线程池大小,默认值10个. 
    建议值:请求高峰时99.5%的平均响应时间 + 向上预留一些即可 
    */  
    HystrixThreadPoolProperties.Setter().withCoreSize(int value)  
    /** 
    配置线程值等待队列长度,默认值:-1 
    建议值:-1表示不等待直接拒绝,测试表明线程池使用直接决绝策略+ 合适大小的非回缩线程池效率最高.所以不建议修改此值。 
    当使用非回缩线程池时,queueSizeRejectionThreshold,keepAliveTimeMinutes 参数无效 
    */  
    HystrixThreadPoolProperties.Setter().withMaxQueueSize(int value)