Hystrix-资源隔离策略(线程、信号量)

1.为什么要进行资源隔离

        比如我们现在有3个业务调用分别是查询订单、查询商品、查询用户,且这三个业务请求都是依赖第三方服务-订单服务、商品服务、用户服务。三个服务均是通过RPC调用。当依赖的订单服务变慢了,而这个时候后续有大量的查询订单请求过来,那么容器中的线程数量则会持续增加直致CPU资源耗尽到100%,整个服务对外不可用,集群环境下就是雪崩。所以,有必要将多个依赖服务的调用分别隔离到各自自己的资源池内,不对其他服务造成影响。如下图:

2. 两种隔离方式  

  Hystrix的隔离策略有两种:分别是线程隔离和信号量隔离。

  THREAD(线程隔离):使用该方式,HystrixCommand将会在单独的线程上执行,并发请求受线程池中线程数量的限制。
  SEMAPHORE(信号量隔离):使用该方式,HystrixCommand将会在调用线程上执行,开销相对较小,并发请求受信号量的个数的限制。

  配置:hystrix.command.default.execution.isolation.strategy 隔离策略,默认是Thread, 可选Thread|Semaphore

2.1 线程隔离(THREAD)

        适用场景:适合绝大多数的场景,对依赖服务的网络调用timeout,TPS要求高的这种问题
        执行依赖代码的线程与请求线程(比如Tomcat线程)分离,请求线程可以自由控制离开的时间,这也是我们通常说的异步编程,Hystrix是结合RxJava来实现的异步编程。通过为每个包裹了HystrixCommand的API接口设置独立的、固定大小的线程池(hystrix.threadpool.default.coreSize)来控制并发访问量,当线程饱和的时候可以拒绝服务(走fallback方法),防止依赖问题扩散。
        线上建议线程池不要设置过大,否则大量堵塞线程有可能会拖慢服务器。

 2.1.1 线程池隔离的优缺点

优点:
    一个依赖调用可以给予一个线程池,这个依赖的异常不会影响其他的依赖。
    使用线程可以完全隔离业务代码,请求线程可以快速返回。
    可以完全模拟异步调用,方便异步编程。

缺点:
    使用线程池的缺点主要是增加了计算的开销。每一个依赖调用都会涉及到队列,调度,上下文切换,而这些操作都有可能在不同的线程中执行。

2.1.2 线程池隔离相关参数

  让我们来逐个介绍下@HystrixCommand注解的各个参数:
  1:commandKey:配置全局唯一标识服务的名称,比如,库存系统有一个获取库存服务,那么就可以为这个服务起一个名字来唯一识别该服务,如果不配置,则默认是@HystrixCommand注解修饰的函数的函数名。


  2:groupKey:一个比较重要的注解,配置全局唯一标识服务分组的名称,比如,库存系统就是一个服务分组。通过设置分组,Hystrix会根据组来组织和统计命令的告、仪表盘等信息。Hystrix命令默认的线程划分也是根据命令组来实现。默认情况下,Hystrix会让相同组名的命令使用同一个线程池,所以我们需要在创建Hystrix命令时为其指定命令组来实现默认的线程池划分。此外,Hystrix还提供了通过设置threadPoolKey来对线程池进行设置。建议最好设置该参数,使用threadPoolKey来控制线程池组。

  例如有如下代码:

 dashboard为

 说明:

findById - HystrixCommandKey(默认为Controller下的方法名)
MovieController - HystrixThreadPoolKey(不配置的情况下就是commandGroupKey,HystrixCommandGroupKey默认为类名)

  3:threadPoolKey:对线程池进行设定,细粒度的配置,相当于对单个服务的线程池信息进行设置,也可多个服务设置同一个threadPoolKey构成线程组。

  4:fallbackMethod:@HystrixCommand注解修饰的函数的回调函数,@HystrixCommand修饰的函数必须和这个回调函数定义在同一个类中,因为定义在了同一个类中,所以fackback method可以是public/private均可。

  5:commandProperties:配置该命令的一些参数,如executionIsolationStrategy配置执行隔离策略,默认是使用线程隔离,此处我们配置为THREAD,即线程池隔离。参见:com.netflix.hystrix.HystrixCommandProperties中各个参数的定义。

  6:threadPoolProperties:线程池相关参数设置,具体可以设置哪些参数请见:com.netflix.hystrix.HystrixThreadPoolProperties

  7:ignoreExceptions:调用服务时,除了HystrixBadRequestException之外,其他@HystrixCommand修饰的函数抛出的异常均会被Hystrix认为命令执行失败而触发服务降级的处理逻辑(调用fallbackMethod指定的回调函数),所以当需要在命令执行中抛出不触发降级的异常时来使用它,通过这个参数指定,哪些异常抛出时不触发降级(不去调用fallbackMethod),而是将异常向上抛出。

  8:observableExecutionMode:定义hystrix observable command的模式;

  9:raiseHystrixExceptions:任何不可忽略的异常都包含在HystrixRuntimeException中;

  10:defaultFallback:默认的回调函数,该函数的函数体不能有入参,返回值类型与@HystrixCommand修饰的函数体的返回值一致。如果指定了fallbackMethod,则fallbackMethod优先级更高。

2.2 信号量隔离(SEMAPHORE)

 

        用于隔离本地代码或可快速返回的远程调用(如memcached,redis)可以直接使用信号量隔离,降低线程隔离的上下文切换开销。

        线程隔离会带来线程开销,有些场景(比如无网络请求场景)可能会因为用开销换隔离得不偿失,为此hystrix提供了信号量隔离。

        主要适用场景: 并发需求不大的依赖调用(因为如果并发需求较大,相应的信号量的数量就要设置得够大,因为Tomcat线程与处理线程为同一个线程,那么这个依赖调用就会占用过多的Tomcat线程资源,有可能会影响到其他服务的接收)

        和线程池隔离类似,同一个HystrixCommandGroupKey共用一个信号量(默认为类名)

public class CommandUsingSemaphoreIsolation extends HystrixCommand<String> {
    private final int id;
    public CommandUsingSemaphoreIsolation(int id) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
                // since we're doing an in-memory cache lookup we choose SEMAPHORE isolation
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));
        this.id = id;
    }
    @Override
    protected String run() {
        // a real implementation would retrieve data from in memory data structure
        return "ValueFromHashMap_" + id;
   }
}

2.3 线程池隔离与信号量隔离区别

线程池隔离:
      1、调用线程和hystrixCommand线程不是同一个线程,并发请求数受到线程池(不是容器tomcat的线程池,而是hystrixCommand所属于线程组的线程池)中的线程数限制,默认是10。
      2、这个是默认的隔离机制
      3、hystrixCommand线程无法获取到调用线程中的ThreadLocal中的值
   信号量隔离:
      1、调用线程和hystrixCommand线程是同一个线程,默认最大并发请求数是10
      2、调用数度快,开销小,由于和调用线程是处于同一个线程,所以必须确保调用的微服务可用性足够高并且返回快才用

注意:如果发生找不到上下文的运行时异常,可考虑将隔离策略设置为SEMAPHONE。

官方图示:

 

posted on 2022-03-02 20:27  胡子就不刮  阅读(4005)  评论(0编辑  收藏  举报

导航