13.亿级流量电商详情页系统实战---hystrix执行流程

高可用系统架构

资源隔离、限流、熔断、降级、运维监控

hystrix可以做到资源,资源隔离有两种,1,线程池的资源隔离 2,信号量的资源隔离

资源隔离

让你的系统里,某一块东西,在故障的情况下,不会耗尽系统所有的资源,比如线程资源

我实际的项目中的一个case,有一块东西,是要用多线程做一些事情,小伙伴做项目的时候,没有太留神,资源隔离,那块代码,在遇到一些故障的情况下,每个线程在跑的时候,因为那个bug,直接就死循环了,导致那块东西启动了大量的线程,每个线程都死循环

最终导致我的系统资源耗尽,崩溃,不工作,不可用,废掉了

资源隔离,那一块代码,最多最多就是用掉10个线程,不能再多了,就废掉了,限定好的一些资源

限流

高并发的流量涌入进来,比如说突然间一秒钟100万QPS,废掉了,10万QPS进入系统,其他90万QPS被拒绝了

熔断

系统后端的一些依赖,出了一些故障,比如说mysql挂掉了,每次请求都是报错的,熔断了,后续的请求过来直接不接收了,拒绝访问,10分钟之后再尝试去看看mysql恢复没有

降级

mysql挂了,系统发现了,自动降级,从内存里存的少量数据中,去提取一些数据出来

运维监控

监控+报警+优化,各种异常的情况,有问题就及时报警,优化一些系统的配置和参数,或者代码

缓存雪崩很恐怖,缓存雪崩,数据库宕机,程序服务还能使用,如何实现?

如何避免缓存雪崩

1、Hystrix是什么?

在分布式系统中,每个服务都可能会调用很多其他服务,被调用的那些服务就是依赖服务,有的时候某些依赖服务出现故障也是很正常的。

Hystrix可以让我们在分布式系统中对服务间的调用进行控制,加入一些调用延迟或者依赖故障的容错机制。

Hystrix通过将依赖服务进行资源隔离,进而组织某个依赖服务出现故障的时候,这种故障在整个系统所有的依赖服务调用中进行蔓延,同时Hystrix还提供故障时的fallback降级机制

总而言之,Hystrix通过这些方法帮助我们提升分布式系统的可用性和稳定性

hystrix,高可用性保障的一个框架

2、初步看一看Hystrix的设计原则是什么?

hystrix为了实现高可用性的架构,设计hystrix的时候,一些设计原则是什么???

(1)对依赖服务调用时出现的调用延迟和调用失败进行控制和容错保护
(2)在复杂的分布式系统中,阻止某一个依赖服务的故障在整个系统中蔓延,服务A->服务B->服务C,服务C故障了,服务B也故障了,服务A故障了,整套分布式系统全部故障,整体宕机
(3)提供fail-fast(快速失败)和快速恢复的支持
(4)提供fallback优雅降级的支持
(5)支持近实时的监控、报警以及运维操作

在这里插入图片描述
在这里插入图片描述

3、Hystrix要解决的问题是什么?

在复杂的分布式系统架构中,每个服务都有很多的依赖服务,而每个依赖服务都可能会故障

如果服务没有和自己的依赖服务进行隔离,那么可能某一个依赖服务的故障就会拖垮当前这个服务

举例来说,某个服务有30个依赖服务,每个依赖服务的可用性非常高,已经达到了99.99%的高可用性

那么该服务的可用性就是99.99%的30次方,也就是99.7%的可用性

99.7%的可用性就意味着3%的请求可能会失败,因为3%的时间内系统可能出现了故障不可用了

对于1亿次访问来说,3%的请求失败,也就意味着300万次请求会失败,也意味着每个月有2个小时的时间系统是不可用的

在真实生产环境中,可能更加糟糕

上面也就是说,即使你每个依赖服务都是99.99%高可用性,但是一旦你有几十个依赖服务,还是会导致你每个月都有几个小时是不可用的

画图分析说,当某一个依赖服务出现了调用延迟或者调用失败时,为什么会拖垮当前这个服务?以及在分布式系统中,故障是如何快速蔓延的?

4、再看Hystrix的更加细节的设计原则是什么?

(1)阻止任何一个依赖服务耗尽所有的资源,比如tomcat中的所有线程资源
(2)避免请求排队和积压,采用限流和fail fast来控制故障
(3)提供fallback降级机制来应对故障
(4)使用资源隔离技术,比如bulkhead(舱壁隔离技术),swimlane(泳道技术),circuit breaker(短路技术),来限制任何一个依赖服务的故障的影响
(5)通过近实时的统计/监控/报警功能,来提高故障发现的速度
(6)通过近实时的属性和配置热修改功能,来提高故障处理和恢复的速度
(7)保护依赖服务调用的所有故障情况,而不仅仅只是网络故障情况

调用这个依赖服务的时候,client调用包有bug,阻塞,等等,依赖服务的各种各样的调用的故障,都可以处理

5、Hystrix是如何实现它的目标的?

(1)通过HystrixCommand或者HystrixObservableCommand来封装对外部依赖的访问请求,这个访问请求一般会运行在独立的线程中,资源隔离
(2)对于超出我们设定阈值的服务调用,直接进行超时,不允许其耗费过长时间阻塞住。这个超时时间默认是99.5%的访问时间,但是一般我们可以自己设置一下
(3)为每一个依赖服务维护一个独立的线程池,或者是semaphore,当线程池已满时,直接拒绝对这个服务的调用
(4)对依赖服务的调用的成功次数,失败次数,拒绝次数,超时次数,进行统计
(5)如果对一个依赖服务的调用失败次数超过了一定的阈值,自动进行熔断,在一定时间内对该服务的调用直接降级,一段时间后再自动尝试恢复
(6)当一个服务调用出现失败,被拒绝,超时,短路等异常情况时,自动调用fallback降级机制
(7)对属性和配置的修改提供近实时的支持

hystrix线程池隔离

线程池隔离,默认有timeout设置,所以在使用线程池隔离技术时,要注意超时时间问题
新建服务 eshop-cache-ha 缓存服务
新建服务eschop-product-ha 商品服务

在这里插入图片描述
以上是商品服务调用异常,造成程序卡顿的情况

如下是缓存服务调用商品服务的入口

/**
 * 缓存服务接口
 */
@Controller
public class CacheController {
    @RequestMapping("/change/product")
    @ResponseBody
    public String changeProduct(Long productId){
        String url = "http://localhost:8082/getProductInfo?productId="+productId;
        String response = HttpClientUtils.sendGetRequest(url);
        System.out.println(response);
        return "success";
    }
}

为了避免商品服务资源耗尽,我们需要在以上代码中,调用商品服务的地方,进行资源隔离

如何资源隔离呢?

引入pom

<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-core</artifactId>
    <version>1.5.12</version>
</dependency>

将商品服务接口调用的逻辑进行封装

hystrix进行资源隔离,其实是提供了一个抽象,叫做command,就是说,你如果要把对某一个依赖服务的所有调用请求,全部隔离在同一份资源池内

对这个依赖服务的所有调用请求,全部走这个资源池内的资源,不会去用其他的资源了,这个就叫做资源隔离

hystrix最最基本的资源隔离的技术,线程池隔离技术

对某一个依赖服务,商品服务,所有的调用请求,全部隔离到一个线程池内,对商品服务的每次调用请求都封装在一个command里面
每个command(每次服务调用请求)都是使用线程池内的一个线程去执行的
所以哪怕是对这个依赖服务,商品服务,现在同时发起的调用量已经到了1000了,但是线程池内就10个线程,最多就只会用这10个线程去执行
不会说,对商品服务的请求,因为接口调用延迟,将tomcat内部所有的线程资源全部耗尽,不会出现了

/**
 * 获取商品信息
 */
public class GetProductInfoCommand  extends HystrixCommand<ProductInfo> {

    private Long productId;

    public GetProductInfoCommand(Long productId){
        super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup"));
        this.productId = productId;

    }

    @Override
    protected ProductInfo run() throws Exception {
        String url = "http://localhost:8082/getProductInfo?productId="+productId;
        String response = HttpClientUtils.sendGetRequest(url);
        System.out.println(response);
        return JSONObject.parseObject(response,ProductInfo.class);
    }
}


/**
 * 批量查询多个商品的command
 */
public class GetProductInfosCommand extends HystrixObservableCommand<ProductInfo> {
    private String[] productIds;

    public GetProductInfosCommand(String[] productIds){
        super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup"));
        this.productIds = productIds;
    }
    @Override
    protected Observable<ProductInfo> construct() {
        return Observable.create(new Observable.OnSubscribe<ProductInfo>() {
            @Override
            public void call(Subscriber<? super ProductInfo> observer) {
                try {
                    //if (!observer.isUnsubscribed()) {

                        for(String productId : productIds){
                            String url = "http://localhost:8082/getProductInfo?productId="+productId;
                            String response = HttpClientUtils.sendGetRequest(url);
                            System.out.println(response);
                            ProductInfo productInfo = JSONObject.parseObject(response,ProductInfo.class);
                            observer.onNext(productInfo);

                        }
                        observer.onCompleted();
                    //}
                } catch (Exception e) {
                    observer.onError(e);
                }
            }
        } ).subscribeOn(Schedulers.io());

    }
}

不让超出这个量的请求去执行了,保护说,不要因为某一个依赖服务的故障,导致耗尽了缓存服务中的所有的线程资源去执行

调用变为

   /**
     * nginx开始,各级缓存都失效了,nginx发送很多请求,直接到缓存服务
     * @param productId
     * @return
     */
    @RequestMapping("/getProductInfo")
    @ResponseBody
    public String getProductInfo(Long productId){
        HystrixCommand<ProductInfo> hystrixCommand = new GetProductInfoCommand(productId);
        ProductInfo productInfo = hystrixCommand.execute();
        System.out.println(productInfo);
        return "success";
    }

    @RequestMapping("/getProductInfos")
    @ResponseBody
    public String getProductInfos(String productIds){
        HystrixObservableCommand<ProductInfo> hystrixCommand = new GetProductInfosCommand(productIds.split(","));
        Observable<ProductInfo> observable = hystrixCommand.observe();
        observable.subscribe(new Observer<ProductInfo>() {
            @Override
            public void onCompleted() {
                System.out.println("获取完了所有的商品数据");
            }

            @Override
            public void onError(Throwable e) {

                e.printStackTrace();
            }

            @Override
            public void onNext(ProductInfo productInfo) {
                System.out.println("onNext: " + productInfo);
            }
        });
        return "success";
    }

command的四种调用方式
同步:new CommandHelloWorld(“World”).execute(),new ObservableCommandHelloWorld(“World”).toBlocking().toFuture().get()
如果你认为observable command只会返回一条数据,那么可以调用上面的模式,去同步执行,返回一条数据
异步:new CommandHelloWorld(“World”).queue(),new ObservableCommandHelloWorld(“World”).toBlocking().toFuture()
对command调用queue(),仅仅将command放入线程池的一个等待队列,就立即返回,拿到一个Future对象,后面可以做一些其他的事情,然后过一段时间对future调用get()方法获取数据

hystrix 信号量隔离

线程池隔离和信号量隔离区别

hystrix 中线程池资源隔离,和信号量资源隔离,都可以做到 规定特定量的线程数的请求,访问资源,那二者有什么区别呢?

在这里插入图片描述

线程池资源隔离,tomcat中的请求线程过来以后,就开始让线程池中的线程进行调度,如果线程池满了以后,会快速失败,调用fallback降级逻辑
fallback是tomcat线程调用,还是线程池中线程调用?

信号量,就是个关卡,tomcat中的请求线程过来以后,关卡会限制有最多有多少个并发,可以同时进入,放行的tomcat线程进入后,会进行程序调度,对于没有放行的tomcat线程会快速调度fallback进行降级

线程池隔离和信号量做资源隔离,都可以起到限流的作用,默认限制容量都是10
二者最大区别是,线程池隔离是让自己定义的线程去执行

信号量是无法做timeout管理的

信号量和线程池资源隔离适用场景

线程池隔离技术和信号量隔离技术,分别在什么样的场景下去使用呢??

线程池:适合绝大多数的场景,99%的,线程池,对依赖服务的网络请求的调用和访问,timeout这种问题

信号量:适合,你的访问不是对外部依赖的访问,而是对内部的一些比较复杂的业务逻辑的访问,但是像这种访问,系统内部的代码,其实不涉及任何的网络请求,那么只要做信号量的普通限流就可以了,因为不需要去捕获timeout类似的问题,算法+数据结构的效率不是太高,并发量突然太高,因为这里稍微耗时一些,导致很多线程卡在这里的话,不太好,所以进行一个基本的资源隔离和访问,避免内部复杂的低效率的代码,导致大量的线程被hang住

业务背景里面, 比较适合信号量的是什么场景呢?

比如说,我们一般来说,缓存服务,可能会将部分量特别少,访问又特别频繁的一些数据,放在自己的纯内存中

一般我们在获取到商品数据之后,都要去获取商品是属于哪个地理位置,省,市,卖家的,可能在自己的纯内存中,比如就一个Map去获取

对于这种直接访问本地内存的逻辑,比较适合用信号量做一下简单的隔离

优点在于,不用自己管理线程池拉,不用care timeout超时了,信号量做隔离的话,性能会相对来说高一些

/**
 * 获取城市名称的command
 */
public class GetCityNameCommand extends HystrixCommand<String/*城市名称*/> {

    private Long cityId;

    public GetCityNameCommand(Long cityId){
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetCityNameGroup"))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)));

        this.cityId = cityId;
    }

    /*默认最多10个线程可以执行这段代码*/
    @Override
    protected String run() throws Exception {
        return LocationCache.getCityName(cityId);
    }
}
public class LocationCache {
    private static Map<Long/*城市id*/,String/*城市名称*/> cityMap = new HashMap<>();

    static {
        cityMap.put(1l, "北京");
    }

    public static String getCityName(Long cityId){
        return cityMap.get(cityId);
    }
}
    @RequestMapping("/getProductInfo")
    @ResponseBody
    public String getProductInfo(Long productId){
        HystrixCommand<ProductInfo> hystrixCommand = new GetProductInfoCommand(productId);

        ProductInfo productInfo = hystrixCommand.execute();


        Long cityId = productInfo.getCityId();

        GetCityNameCommand getCityNameCommand = new GetCityNameCommand(cityId);
        String cityName = getCityNameCommand.execute();
        productInfo.setCityName(cityName);
        System.out.println(productInfo);

        //异步方式
//        Future<ProductInfo> future = hystrixCommand.queue();
//        try{
//            Thread.sleep(10000);
//            System.out.println(future.get());
//        }catch (Exception e){
//
//        }
        return "success";
    }

资源隔离粒度控制

1、execution.isolation.strategy
2、command名称和command组
3、command线程池
4、coreSize
5、queueSizeRejectionThreshold
6、execution.isolation.semaphore.maxConcurrentRequests

1、execution.isolation.strategy

指定了HystrixCommand.run()的资源隔离策略,THREAD或者SEMAPHORE,一种是基于线程池,一种是信号量

线程池机制,每个command运行在一个线程中,限流是通过线程池的大小来控制的

信号量机制,command是运行在调用线程中,但是通过信号量的容量来进行限流

如何在线程池和信号量之间做选择?

默认的策略就是线程池

线程池其实最大的好处就是对于网络访问请求,如果有超时的话,可以避免调用线程阻塞住

而使用信号量的场景,通常是针对超大并发量的场景下,每个服务实例每秒都几百的QPS,那么此时你用线程池的话,线程一般不会太多,可能撑不住那么高的并发,如果要撑住,可能要耗费大量的线程资源,那么就是用信号量,来进行限流保护

一般用信号量常见于那种基于纯内存的一些业务逻辑服务,而不涉及到任何网络访问请求

netflix有100+的command运行在40+的线程池中,只有少数command是不运行在线程池中的,就是从纯内存中获取一些元数据,或者是对多个command包装起来的facacde command,是用信号量限流的

// to use thread isolation
HystrixCommandProperties.Setter()
   .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)
// to use semaphore isolation
HystrixCommandProperties.Setter()
   .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)

2、command名称和command组

线程池隔离,依赖服务->接口->线程池,如何来划分

你的每个command,都可以设置一个自己的名称,同时可以设置一个自己的组

private static final Setter cachedSetter = 
    Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
        .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"));    

public CommandHelloWorld(String name) {
    super(cachedSetter);
    this.name = name;
}

command group,是一个非常重要的概念,默认情况下,因为就是通过command group来定义一个线程池的,而且还会通过command group来聚合一些监控和报警信息

同一个command group中的请求,都会进入同一个线程池中


3、command线程池

threadpool key代表了一个HystrixThreadPool,用来进行统一监控,统计,缓存

默认的threadpool key就是command group名称

每个command都会跟它的threadpool key对应的thread pool绑定在一起

如果不想直接用command group,也可以手动设置thread pool name

public CommandHelloWorld(String name) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
            .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
            .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
    this.name = name;
}

command threadpool -> command group -> command key

command key,代表了一类command,一般来说,代表了底层的依赖服务的一个接口

command group,代表了某一个底层的依赖服务,合理,一个依赖服务可能会暴露出来多个接口,每个接口就是一个command key

command group,在逻辑上去组织起来一堆command key的调用,统计信息,成功次数,timeout超时次数,失败次数,可以看到某一个服务整体的一些访问情况

command group,一般来说,推荐是根据一个服务去划分出一个线程池,command key默认都是属于同一个线程池的

比如说你以一个服务为粒度,估算出来这个服务每秒的所有接口加起来的整体QPS在100左右

你调用那个服务的当前服务,部署了10个服务实例,每个服务实例上,其实用这个command group对应这个服务,给一个线程池,量大概在10个左右,就可以了,你对整个服务的整体的访问QPS大概在每秒100左右

一般来说,command group是用来在逻辑上组合一堆command的

举个例子,对于一个服务中的某个功能模块来说,希望将这个功能模块内的所有command放在一个group中,那么在监控和报警的时候可以放一起看

command group,对应了一个服务,但是这个服务暴露出来的几个接口,访问量很不一样,差异非常之大

你可能就希望在这个服务command group内部,包含的对应多个接口的command key,做一些细粒度的资源隔离

对同一个服务的不同接口,都使用不同的线程池

command key -> command group

command key -> 自己的threadpool key

逻辑上来说,多个command key属于一个command group,在做统计的时候,会放在一起统计

每个command key有自己的线程池,每个接口有自己的线程池,去做资源隔离和限流

但是对于thread pool资源隔离来说,可能是希望能够拆分的更加一致一些,比如在一个功能模块内,对不同的请求可以使用不同的thread pool

command group一般来说,可以是对应一个服务,多个command key对应这个服务的多个接口,多个接口的调用共享同一个线程池

如果说你的command key,要用自己的线程池,可以定义自己的threadpool key,就ok了

4、coreSize

设置线程池的大小,默认是10

HystrixThreadPoolProperties.Setter()
   .withCoreSize(int value)

一般来说,用这个默认的10个线程大小就够了
在这里插入图片描述

5、queueSizeRejectionThreshold

控制queue满后reject的threshold,因为maxQueueSize不允许热修改,因此提供这个参数可以热修改,控制队列的最大大小

HystrixCommand在提交到线程池之前,其实会先进入一个队列中,这个队列满了之后,才会reject

默认值是5

HystrixThreadPoolProperties.Setter()
   .withQueueSizeRejectionThreshold(int value)

在这里插入图片描述

6、execution.isolation.semaphore.maxConcurrentRequests

设置使用SEMAPHORE隔离策略的时候,允许访问的最大并发量,超过这个最大并发量,请求直接被reject

这个并发量的设置,跟线程池大小的设置,应该是类似的,但是基于信号量的话,性能会好很多,而且hystrix框架本身的开销会小很多

默认值是10,设置的小一些,否则因为信号量是基于调用线程去执行command的,而且不能从timeout中抽离,因此一旦设置的太大,而且有延时发生,可能瞬间导致tomcat本身的线程资源本占满

HystrixCommandProperties.Setter()
   .withExecutionIsolationSemaphoreMaxConcurrentRequests(int value)

在这里插入图片描述

Hystrix执行流程

在这里插入图片描述

1、构建一个HystrixCommand或者HystrixObservableCommand

HystrixCommand主要用于仅仅会返回一个结果的调用
HystrixObservableCommand主要用于可能会返回多条结果的调用

2、调用command的执行方法

执行Command就可以发起一次对依赖服务的调用

要执行Command,需要在4个方法中选择其中的一个:execute(),queue(),observe(),toObservable()

其中execute()和queue()仅仅对HystrixCommand适用

execute():调用后直接block住,属于同步调用,直到依赖服务返回单条结果,或者抛出异常
queue():返回一个Future,属于异步调用,后面可以通过Future获取单条结果
observe():订阅一个Observable对象,Observable代表的是依赖服务返回的结果,获取到一个那个代表结果的Observable对象的拷贝对象
toObservable():返回一个Observable对象,如果我们订阅subscribe这个对象,就会执行command并且获取返回结果

K             value   = command.execute();
Future<K>     fValue  = command.queue();
Observable<K> ohValue = command.observe();         
Observable<K> ocValue = command.toObservable();    

execute()实际上会调用queue().get().queue(),接着会调用toObservable().toBlocking().toFuture()

也就是说,无论是哪种执行command的方式,最终都是依赖toObservable()去执行的

3、检查是否开启缓存

如果这个command开启了请求缓存,request cache,而且这个调用的结果在缓存中存在,那么直接从缓存中返回结果

4、检查是否开启了短路器

检查这个command对应的依赖服务是否开启了短路器

如果断路器被打开了,那么hystrix就不会执行这个command,而是直接去执行fallback降级机制

5、检查线程池/队列/semaphore是否已经满了

如果command对应的线程池/队列/semaphore已经满了,那么也不会执行command,而是直接去调用fallback降级机制

6、执行command

调用HystrixObservableCommand.construct()或HystrixCommand.run()来实际执行这个command

HystrixCommand.run()是返回一个单条结果,或者抛出一个异常
HystrixObservableCommand.construct()是返回一个Observable对象,可以获取多条结果

如果HystrixCommand.run()或HystrixObservableCommand.construct()的执行,超过了timeout时长的话,那么command所在的线程就会抛出一个TimeoutException

如果timeout了,也会去执行fallback降级机制,而且就不会管run()或construct()返回的值了

这里要注意的一点是,我们是不可能终止掉一个调用严重延迟的依赖服务的线程的,只能说给你抛出来一个TimeoutException,但是还是可能会因为严重延迟的调用线程占满整个线程池的

即使这个时候新来的流量都被限流了。。。

如果没有timeout的话,那么就会拿到一些调用依赖服务获取到的结果,然后hystrix会做一些logging记录和metric统计

7、短路健康检查

Hystrix会将每一个依赖服务的调用成功,失败,拒绝,超时,等事件,都会发送给circuit breaker断路器

短路器就会对调用成功/失败/拒绝/超时等事件的次数进行统计

短路器会根据这些统计次数来决定,是否要进行短路,如果打开了短路器,那么在一段时间内就会直接短路,然后如果在之后第一次检查发现调用成功了,就关闭断路器

8、调用fallback降级机制

在以下几种情况中,hystrix会调用fallback降级机制:

run()或construct()抛出一个异常,
短路器打开,
线程池/队列/semaphore满了,
command执行超时了

一般在降级机制中,都建议给出一些默认的返回值,比如静态的一些代码逻辑,或者从内存中的缓存中提取一些数据,尽量在这里不要再进行网络请求了

即使在降级中,一定要进行网络调用,也应该将那个调用放在一个HystrixCommand中,进行隔离

在HystrixCommand中,上线getFallback()方法,可以提供降级机制

在HystirxObservableCommand中,实现一个resumeWithFallback()方法,返回一个Observable对象,可以提供降级结果

如果fallback返回了结果,那么hystrix就会返回这个结果

对于HystrixCommand,会返回一个Observable对象,其中会发返回对应的结果
对于HystrixObservableCommand,会返回一个原始的Observable对象

如果没有实现fallback,或者是fallback抛出了异常,Hystrix会返回一个Observable,但是不会返回任何数据

不同的command执行方式,其fallback为空或者异常时的返回结果不同

对于execute(),直接抛出异常
对于queue(),返回一个Future,调用get()时抛出异常
对于observe(),返回一个Observable对象,但是调用subscribe()方法订阅它时,理解抛出调用者的onError方法
对于toObservable(),返回一个Observable对象,但是调用subscribe()方法订阅它时,理解抛出调用者的onError方法

不同的执行方式

execute(),获取一个Future.get(),然后拿到单个结果
queue(),返回一个Future
observer(),立即订阅Observable,然后启动8大执行步骤,返回一个拷贝的Observable,订阅时理解回调给你结果
toObservable(),返回一个原始的Observable,必须手动订阅才会去执行8大步骤

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值