美文网首页
Hystrix快速入门(3) Hystrix资源隔离策略(线程、

Hystrix快速入门(3) Hystrix资源隔离策略(线程、

作者: 沉沦2014 | 来源:发表于2018-08-29 17:22 被阅读36次

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

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

    image.png
    *

    2. 两种隔离方式

    2.1 线程隔离

    适用场景适合绝大多数的场景,对依赖服务的网络调用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来控制线程池组。
    例如有如下代码:

    image.png
    image.png
    dashboard为:
    image.png
    说明:
    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 信号量隔离

    用于隔离本地代码或可快速返回的远程调用(如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 线程池隔离与信号量隔离区别

    官方图示:


    image.png
    image.png

    相关文章

      网友评论

          本文标题:Hystrix快速入门(3) Hystrix资源隔离策略(线程、

          本文链接:https://www.haomeiwen.com/subject/tzehwftx.html