Hystrix组件提供了两种隔离的解决方案:线程池隔离和信号量隔离。两种隔离方式都是限制对共享资源的并发访问量,线程在就绪状态、运行状态、阻塞状态、终止状态间转变时需要由操作系统调度,占用很大的性能消耗;而信号量是在访问共享资源时,进行tryAcquire,tryAcquire成功才允许访问共享资源。
 
线程池隔离
     不同的业务线之间选择用线程池隔离,降低互相影响的概率。设置隔离策略为线程池隔离:
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD));在Hystrix内部,是根据properties.executionIsolationStrategy().get()这个字段判断隔离级别。如在getRunObservableDecoratedForMetricsAndErrorHandling这个方法中会先判断是不是线程池隔离,如果是就获取线程池,如果不是则进行信号量隔离的操作。
     如果是线程池隔离,还需要设置线程池的相关参数如:线程池名字andThreadPoolKey , coreSize(核心线程池大小) , KeepAliveTimeMinutes(线程存存活时间),MaxQueueSize(最大队列长度),QueueSizeRejectionThreshold(拒绝执行的阀值)等等。
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(resourcesManager.getThreadPoolProperties(platformProtocol.getAppId()).getCoreSize())
                                    .withKeepAliveTimeMinutes(resourcesManager.getThreadPoolProperties(platformProtocol.getAppId()).getKeepAliveSeconds())
                                    .withMaxQueueSize(resourcesManager.getThreadPoolProperties(platformProtocol.getAppId()).getMaxQueueSize())
                                    .withQueueSizeRejectionThreshold(resourcesManager.getThreadPoolProperties(platformProtocol.getAppId()).getQueueSizeRejectionThreshold()))
threadPoolKey 也是线程池的名字的前缀,默认前缀是 hystrix 。在Hystrix中,核心线程数和最大线程数是一致的,减少线程临时创建和销毁带来的性能开销。线程池的默认参数都在HystrixThreadPoolProperties中,重点讲解一下参数queueSizeRejectionThreshold 和maxQueueSize 。queueSizeRejectionThreshold默认值是5,允许在队列中的等待的任务数量。maxQueueSize默认值是-1,队列大小。如果是Fast Fail 应用,建议使用默认值。线程池饱满后直接拒绝后续的任务,不再进行等待。代码如下HystrixThreadPool类中:
@Override
        public boolean isQueueSpaceAvailable() {
            if (queueSize <= 0) {
                // we don't have a queue so we won't look for space but instead
                // let the thread-pool reject or not
                return true;
            } else {
                return threadPool.getQueue().size() < properties.queueSizeRejectionThreshold().get();
            }
        }
 
线程池一旦创建完成,相关参数就不会更改,存放在静态的ConcurrentHashMap中,key是对应的commandKey 。而queueSizeRejectionThreshold是每个命令都是设置的。
 
 
     
     线程池的相关参数都保存在HystrixThreadPool这个类文件中,线程池的创建方法getThreadPool则在HystrixConcurrencyStrategy类文件中。从getThreadPool方法可以看出线程池的名字就是hystrix-threadPoolKey-threadNumber.
@Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r, "hystrix-" + threadPoolKey.name() + "-" + threadNumber.incrementAndGet());
                thread.setDaemon(true);
                return thread;
            }
     
     在HystrixThreadPool实现类的构造方法中,并发HystrixConcurrencyStrategy实例是通过HystrixPlugins获取的,所以可以通过HystrixPlugins设置自定义插件。具体的HystrixPlugins如何使用,会在后面章节中讲解。
 
线程池的创建     
     前面说了,在Hystrix内部大部分类都是单实例,同样ThreadPool也不例外,也是单实例。并且相同commandKey的依赖还必须是使用同一个线程池。这就需要把ThreadPool保存在一个静态的map中,key是commandKey,同时要保证线程安全,Hytstrix使用了ConcurrentHashMap。关于为什么不适用HashTable保证线程安全问题的疑问请自行Google。线程池的创建在HystrixThreadPool这个类文件中的内部类Factory中的getInstance方法。
 
/* package */final static ConcurrentHashMap<String, HystrixThreadPool> threadPools = new ConcurrentHashMap<String, HystrixThreadPool>();
     String key = threadPoolKey.name();

            // this should find it for all but the first time
            HystrixThreadPool previouslyCached = threadPools.get(key);
            if (previouslyCached != null) {
                return previouslyCached;
            }

// if we get here this is the first time so we need to initialize
            synchronized (HystrixThreadPool.class) {
                if (!threadPools.containsKey(key)) {
                    threadPools.put(key, new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder));
                }
            }

            return threadPools.get(key);
     
线程池的使用
     HystrixCommand类的execute()内部调用了queue() ,queue又调用了父类AbstractCommand的toObservable方法,toObservable方法处理了是否可缓存问题后,交给了getRunObservableDecoratedForMetricsAndErrorHandling方法,这个方法设置了一系列的executionHook之后,交给了getExecutionObservableWithLifecycle,这个方法通过getExecutionObservable()获取了执行器。getExecutionObservable()是个抽象方法,具体实现放在了子类:HystrixCommand和HystrixObservableCommand类中。下面是HystrixCommand类中的getExecutionObservable方法实现:
final protected Observable<R> getExecutionObservable() {
        return Observable.create(new OnSubscribe<R>() {

@Override
            public void call(Subscriber<? super R> s) {
                try {
                    s.onNext(run());
                    s.onCompleted();
                } catch (Throwable e) {
                    s.onError(e);
                }
            }

});
    }

在这个Call方法中执行了具体的业务逻辑run() ;
 
转自
 

Spring Cloud Hystrix熔断器隔离方案的更多相关文章

  1. Spring Cloud Hystrix 熔断器(五)

    序言 感觉hystrix很精彩,文档讲的也很好,这篇总结到哪里是哪里吧 写Hystrix之前,我们先简单的说说熔断器,和限流,这样你看完之后,就可以很容易理解Hystrix 熔断器 熔断器模式源于Ma ...

  2. Spring Cloud Hystrix——熔断器

    1.雪崩效应在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应.服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费者 ...

  3. spring cloud hystrix的隔离策略和dashboard

    随着服务的拆分,各个服务有着明确的职责,服务之间通过轻量级的协议进行通讯.但有时候我们完成一个功能需要同时调用多个微服务,比如完成订单的创建,那么获取用户信息需要调用用户微服务,获取商品信息需要调用商 ...

  4. spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略

    spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略 某电子商务网站在一个黑色星期五 ...

  5. Spring Cloud Hystrix 1(熔断器简介)

    在分布式框架中当某个服务单元发生故障之后通过断路器的故障监控向调用方返回一个错误响应,而不是长期等待这样就不会使得线程因调用故障服务被长时间占用不放,避免了故障在分布式系统中的蔓延 针对上述问题,Sp ...

  6. Spring Cloud 微服务四:熔断器Spring cloud hystrix

    前言:在微服务架构中,一般都是进程间通信,有可能调用链都比较长,当有底层某服务出现问题时,比如宕机,会导致调用方的服务失败,这样就会发生一连串的反映,造成系统资源被阻塞,最终可能造成雪崩.在sprin ...

  7. Spring Cloud Hystrix 服务容错保护

    目录 一.Hystrix 是什么 二.Hystrix断路器搭建 三.断路器优化 一.Hystrix 是什么 ​ 在微服务架构中,我们将系统拆分成了若干弱小的单元,单元与单元之间通过HTTP或者TCP等 ...

  8. 分布式系统的延时和故障容错之Spring Cloud Hystrix

    本示例主要介绍 Spring Cloud 系列中的 Eureka,如何使用Hystrix熔断器容错保护我们的应用程序. 在微服务架构中,系统被拆分成很多个服务单元,各个服务单元的应用通过 HTTP 相 ...

  9. Spring Cloud Hystrix 服务容错保护 5.1

    Spring Cloud Hystrix介绍 在微服务架构中,通常会存在多个服务层调用的情况,如果基础服务出现故障可能会发生级联传递,导致整个服务链上的服务不可用为了解决服务级联失败这种问题,在分布式 ...

随机推荐

  1. 留学萌新Essay写作须知

    Essay是留学生们接触比较多的一项留学生作业,但尽管如此,依旧有部分同学对于essay写作是没有足够的把握的.随着开学季的到来,很多萌新初次接触Essay写作,难免会有很多不懂得地方.所以今天小编就 ...

  2. php srand()和rand()

    1.rand()函数 作用:返回随机整数 用法:rand(min,max)  min和max规定随机数产生的范围,可以省略不写,不写时rand() 返回 0 到 RAND_MAX 之间的伪随机整数. ...

  3. UVA - 1153 Keep the Customer Satisfied(顾客是上帝)(贪心)

    题意:有n(n<=800000)个工作,已知每个工作需要的时间qi和截止时间di(必须在此之前完成),最多能完成多少个工作?工作只能串行完成.第一项任务开始的时间不早于时刻0. 分析:按截止时间 ...

  4. UVA - 10954 Add All (全部相加)(Huffman编码 + 优先队列)

    题意:有n(n <= 5000)个数的集合S,每次可以从S中删除两个数,然后把它们的和放回集合,直到剩下一个数.每次操作的开销等于删除的两个数之和,求最小总开销.所有数均小于10^5. 分析:按 ...

  5. Egret Engine 2D - 缩放模式和旋转模式说明

    缩放模式和旋转模式说明 缩放模式showAll 常用 noScale noBorder exactFit 次常用 fixedWidth fixedHeight fixedNarrow fixedWid ...

  6. cf 755D. PolandBall and Polygon

    题意:把一个多边形往里面连对角线,然后问每次添加多边形被划分为几个部分 产生的部分就是新加对角线与原有对角线相交条数+1,用线段树(大雾)维护一下. #include<bits/stdc++.h ...

  7. 剑指offer_1.24_Day_4

    构建乘积数组 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1] ...

  8. 安装swoole redis异步 hiredis swoole扩展加载失败 或者不显示问题 解决办法

    当前办法仅供参考 贴上报错 找了好久 根据网上办法也试了 没解决 最后 仔细读问题 觉得可能是 hiredis路径问题 终于解决了 解决办法: 进入你的安装包目录然后执行下面 mkdir /usr/l ...

  9. Java UDP发送与接收

    IP地址?端口号?主机名? 什么是Socket? 什么是UDP? 什么是TCP? UDP和TCP区别? 以上问题请自行百度,有标准解释,此处不再赘述,直接上干货! 实例: 发送端: public cl ...

  10. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring Bean的生命周期

    Spring 容器可以管理 singleton 作用域 Bean 的生命周期,在此作用域下,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁. 而对于 protot ...