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. Win10下用selenium、Image.crop() 截图时、坐标不准确的问题

    截百度按钮的图 先将整个窗口的图保存下来 from selenium import webdriver driver = webdriver.Chrome() driver.get('https:// ...

  2. Wdcp升级Php5.3成功

    在lanmp/wdcp/wdOS的当前版本中,默认的php都是用到5.2.17的版本如需要升级到php5.3的,可使用如下脚本升级(注:此升级无安全漏洞等原因,只为某些追求高版本或应用需求需要高版本, ...

  3. ES6中字符串的新增方法梳理

    1.String.fromCodePoint(); String,fromCodePoint()方法可以认为是对String.fromCharCode()方法的扩展,这两个方法的共同点在于都是用于Un ...

  4. 执行 composer update 命令的时候报 Your requirements could not be resolved to an installable set of packages. 错误

    Your requirements could not be resolved to an installable set of packages. 以上原因:不匹配composer.json要求的版 ...

  5. 51nod 1287: 加农炮 好题啊好题

    1287 加农炮 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 一个长度为M的正整数数组A,表示从左向右的地形高度. ...

  6. openstack trove实例状态转换条件--Mitaka版本

    今天研究了一下trove的instance状态转换条件.发现其实设计的挺复杂的.后来思考了一下这样设计的原因.我觉得大致是因为,如果instance的状态全部来自于instance上跑的数据库服务本身 ...

  7. oracle(3)select语句中常用的关键字说明

    1.select 查询表中的数据 select * from stu: ---查询stu表所有的数据,*代表所有2.dual ,伪表,要查询的数据不存在任何表中时使用 select sysdate f ...

  8. 在MFC做DLL动态链接库时,使用boost,出现断言错误

    建立的MFC DLL工程中有使用boost::thread,就会发生compile正常但是一程式执行或者直接编辑就出現ASSERT错误. 错误位置:dllinit.cpp,Line: 587,ASSE ...

  9. zookeeper基础教程

    一.关于zookeeper Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于类似于文件系统的目录节点树方式的数据存储, Zookeeper 作用 ...

  10. 十分简明易懂的FFT(快速傅里叶变换)

    https://blog.csdn.net/enjoy_pascal/article/details/81478582 FFT前言快速傅里叶变换 (fast Fourier transform),即利 ...