zoukankan      html  css  js  c++  java
  • Hystrix核心基础

    前言

    RxJava可能有些小伙伴没有听过是什么东西,可能是因为大家平时在做业务需求的时候对异步编程了解得比较少,而RxJava就是这么一个响应式编程框架,RxJava在安卓上面用得非常多,做安卓的朋友肯定对它很熟悉。那我这里为什么要讲这个呢?因为spring cloud中服务治理框架Hystrix中大量用到了RxJava的响应式编程,为了便于理解,这里也简单给大家介绍一下。这里介绍的版本是RxJava 1.X版本的, 而在去年的早些时候,官方便宣布,将在一段时间后不再对 RxJava 1.x 进行维护,推出了RxJava2.X版本,既然有新的,为什么不介绍新的呢?因为目前最新的Hystrix版本1.5.12中使用的RxJava是1.2版本的,而2.X版本的api改动还是比较大的,所以为了大家能更加简单的理解Hystrix,所以这里是对1.X版本的介绍。

    响应式编程是什么

    响应式编程是一种基于异步数据流概念的编程模式,有点类似于JAVA里面的lambda表达式,相信大家都很熟悉lambda吧。数据流,stream,大家肯定不陌生,我们可以对stream有很多操作,filter、map、reduce 等常见操作。然后响应式中的核心就是响应二字,响应什么呢?响应的是事件,event 。 而流就是一个按照时间进行排序的事件序列。RxJava里面的事件是基于观察者模式,事件流将从上往下,从订阅源传递到观察者。

    RxJava中重要概念

    RxJava 有四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 Subscriber (订阅,是Observer的抽象实现类,本质上使用是一样的)、事件。ObservableObserver 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 ObserverObservable 就像是一个生产者,在不断的生产消息,而SubscriberObserver 就像是一个消费者,在不断的消费消息

    另外, RxJava 的事件回调方法还定义了两个特殊的事件,在Hystrix中用得也非常多:onCompleted()onError()

    • onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。
    • onError(): 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。

    怎么做

    说了这么多概念,估计大家都是一头雾水,我们直接来些实际的,加深大家的印象理解。用多的自然而然就会了,就懂了,这里说得可能不是最全的,但是说的都是Hystrix中用得很多的一些操作符,加深大家对Hystrix的理解,看源码就会容易一些。

    例子

    Observable<String> producer = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
    subscriber.onNext("apple");
    subscriber.onNext("orange");
    subscriber.onCompleted();
    }
    });
    Subscriber<String> consumer = new Subscriber<String>() {
    @Override
    public void onNext(String s) {
    LOG.info("我收到的水果有 = {}" , s);
    }
    @Override
    public void onCompleted() {
    }
    @Override
    public void onError(Throwable e) {
    }
    };
    producer.subscribe(consumer);

    先来一个简单的例子给大家直观的介绍下ObservableSubscriber 做了些什么,Observable 使用了onNext方法生产了2个水果,Apple和orange ,然后调用了onCompleted方法结束了这次生产, 消费者用onnext方法收到了2个水果,所以消费者就将收到的水果打印出来了,没有做任何处理

    执行结果如下:

    2018-04-27 10:21:11.440 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :我收到的水果有 = apple
    2018-04-27 10:21:11.440 INFO [#][#] <main> com.dzy.learn.other.NormalTest :我收到的水果有 = orange

    然后再给大家介绍一下Hystrix中用得非常多的操作符

    create

    Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
    subscriber.onNext("item1");
    subscriber.onNext("item2");
    subscriber.onCompleted();
    }
    });
    //在上面的例子中已经跟大家讲过了,create就是创建一个Observable,来生产消息

    from

    List<String> fruitList = Arrays.asList("apple","orange");
    Observable.from(fruitList).subscribe(new Action1<String>() {
    @Override
    public void call(String fruit) {
    LOG.info("fruit = {}" , fruit);
    }
    });

    上面订阅者的代码被我简化了,直接new 一个Action1, 是subscribe支持的一种订阅方式,跟Subscriber是一样的道理,只是更加简化。然后我们再用lambda表达式简化一下就是这样的了

    List<String> fruitList = Arrays.asList("apple","orange");
    Observable.from(fruitList).subscribe(fruit -> LOG.info("fruit = {}" , fruit));

    执行结果如下:

    2018-04-27 10:30:59.030 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :fruid = apple
    2018-04-27 10:30:59.030 INFO [#][#] <main> com.dzy.learn.other.NormalTest :fruid = orange

    defer

    只有当订阅者订阅才创建Observable,为每个订阅创建一个新的Observable。内部通过OnSubscribeDefer在订阅时调用Func0创建Observable

    List<String> fruitList = Arrays.asList("apple","orange");
    Observable.defer(new Func0<Observable<String>>() {
    @Override
    public Observable<String> call() {
    return Observable.from(fruitList);
    }
    }).subscribe(new Action1<String>() {
    @Override
    public void call(String fruit) {
    LOG.info("defer fruit = {}" , fruit);
    }
    });

    不知道大家理解了没有,每次生产消息都会生产一个新的消息生产者

    执行结果如下:

    2018-04-27 10:37:26.209 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :defer fruit = apple
    2018-04-27 10:37:26.209 INFO [#][#] <main> com.dzy.learn.other.NormalTest :defer fruit = orange

    startWith

    在生产的第一个消息前加上一个或者一些消息,看例子比较直观

     List<String> fruitList = Arrays.asList("apple","orange");
    Observable.from(fruitList)
    .startWith("before apple","before apple2")
    .subscribe(fruit->LOG.info("fruit = {}" , fruit));

    执行结果如下:

    2018-04-27 10:40:52.221 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :fruit = before apple
    2018-04-27 10:40:52.221 INFO [#][#] <main> com.dzy.learn.other.NormalTest :fruit = before apple2
    2018-04-27 10:40:52.222 INFO [#][#] <main> com.dzy.learn.other.NormalTest :fruit = apple
    2018-04-27 10:40:52.222 INFO [#][#] <main> com.dzy.learn.other.NormalTest :fruit = orange

    Filter

    跟lambda里面的filter很像,也是用来筛选数据的,filter接收的Func1第二个参数是Boolean,定死的

    List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0);
    Observable.from(list)
    .filter(new Func1<Integer, Boolean>() {
    @Override
    public Boolean call(Integer integer) {
    return integer>4;
    }
    })
    .subscribe(num->LOG.info("比4大的num = {}" , num));

    Map

    Map是将需要生产的数据经过Func1进行变换之后,然后在发送给消费者。第二个参数是Object类型的,可以转化成一个Object对象

    List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0);
    Observable.from(list)
    .map(new Func1<Integer, Object>() {
    @Override
    public Object call(Integer integer) {
    return integer+"变成str";
    }
    })
    .subscribe(s -> LOG.info("s = {}" , s));

    输出如下:

    2018-04-27 11:08:02.743 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :s = 10变成str
    2018-04-27 11:08:02.747 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 5变成str
    2018-04-27 11:08:02.747 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 3变成str
    2018-04-27 11:08:02.748 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 2变成str
    2018-04-27 11:08:02.748 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 1变成str
    2018-04-27 11:08:02.748 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 0变成str

    FlatMap

    跟map有些类似,但是也有很大的区别,map是一个对象变成另外一个对象,而flatMap可以把一个对象转化为多个对象 , 其实FlatMap是将一个对象转成了一个Observable 对象,转完之后,最开始的生产者并不发送这个 Observable, 而是将它激活,于是它开始发送事件,每一个创建出来的 Observable 发送的事件,都被汇入同一个 Observable ,而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法,这样也就产生了一对多的概念,就像是把对象铺平了一样,flat

    我会跟lambda的flatMap做一个对比,还是很像的

    List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0);
    List<Object> flatMapcollect = list.stream().flatMap(new Function<Integer, Stream<?>>() {
    @Override
    public Stream<?> apply(Integer integer) {
    //通过list里面的元素创建一个list返回回去
    List<Integer> list1 = Arrays.asList(integer, integer + 10, integer + 100, integer + 1000);
    return list1.stream();
    }
    }).collect(Collectors.toList());
    flatMapcollect.forEach(s->LOG.info("complex integer = {}" , s));

    打印的结果是一开始的每个元素10 ,5等都被加上了10 100 1000 然后输出了,相当于平铺了

    2018-04-27 11:50:21.186 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :complex integer  = 10   // 10本来数字
    2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 20 //加上10之后
    2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 110 //加上100之后
    2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 1010 //加上1000之后
    2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 5
    2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 15
    2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 105
    2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 1005
    //限于篇幅,后面的略,都是 源数 加上10 100 1000后输出的

    RxJava里面的flatMap, 我乘以10,乘以100然后加下|转成一个String

    List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0);

    Observable.from(list).flatMap(new Func1<Integer, Observable<?>>() {
    @Override
    public Observable<?> call(Integer num) {
    List<String> strings = Arrays.asList("|" + num + "|", "|" + num * 10 + "|", "|" + num * 100 + "|");
    return Observable.from(strings);
    }
    }).subscribe(new Action1<Object>() {
    @Override
    public void call(Object o) {
    LOG.info("新转化后的字符串是 = {}" , o);
    }
    });

    输出如下:

    2018-04-27 11:57:13.316 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |10|
    2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |100|
    2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |1000|
    2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |5|
    2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |50|
    2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |500|
    2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |3|
    2018-04-27 11:57:13.321 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |30|
    2018-04-27 11:57:13.321 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |300|

    reduce

    reduce是一个聚合函数,接收上次运算的结果,放在下次的参数中,然后输出最后的结果,结果只输出一次。有点类似于递归。跟scan操作符很像,但是有区别,大家看下scan的输出就知道是什么区别了。

    RxJava里面的reduce

    Observable.from(list).reduce(new Func2<Integer, Integer, Integer>() {
    @Override
    public Integer call(Integer result, Integer num) {
    LOG.info("开始前: result {}, num = {}" , result,num);
    result+=num;
    return result;
    }
    }).subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer result) {
    LOG.info("result = {}" , result);
    }
    });

    打印结果如下:

    2018-04-27 13:47:29.237 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 10, num = 5
    2018-04-27 13:47:29.241 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 15, num = 3
    2018-04-27 13:47:29.241 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 18, num = 2
    2018-04-27 13:47:29.241 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 20, num = 1
    2018-04-27 13:47:29.241 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 21, num = 0
    2018-04-27 13:47:29.241 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 21

    lambda里面的reduce

    List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0);

    Integer sum = list.stream().reduce((result, sum1) -> {
    result += sum1;
    return result;
    }).get();
    LOG.info("sum = {}" , sum);
    //sum是21,就是累加起来

    scan

    scan和reduce都是把上一次操作的结果做为第二次的参数传递给第二次Observable使用,但是scan每次操作之后先把数据输出,然后在调用scan的回调函数进行第二次操作,看例子

    Observable.from(list)
    .scan(new Func2<Integer, Integer, Integer>() {
    @Override
    public Integer call(Integer result, Integer num) {
    LOG.info("开始前: result {}, num = {}" , result,num);
    result+=num;
    return result;
    }
    }).subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer result) {
    LOG.info("result = {}" , result);
    }
    });
    2018-04-27 13:47:29.245 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :result = 10
    2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 10, num = 5
    2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 15
    2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 15, num = 3
    2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 18
    2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 18, num = 2
    2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 20
    2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 20, num = 1
    2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 21
    2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 21, num = 0
    2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 21

    每次运算后都会调用订阅者

    window

    Hystrix 滑动窗口的核心用的就是window操作符,那么window有什么作用呢?他能将Observable的数据分拆成一些Observable窗口,然后把Observable窗口推送给订阅者,而不是一个数据,是一个Observable。来点例子更加直白

    window(int count, int skip)
    List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0);
    Observable.from(list).window(2, 2).subscribe(new Action1<Observable<Integer>>() {
    @Override
    public void call(Observable<Integer> integerObservable) {
    integerObservable.reduce((sum, num) -> sum+=num).subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer integer) {
    LOG.info("我被2个打印一次 = {}" , integer);
    }
    });
    }
    });

    window里面有2个参数,第一个参数2 表示 选取2个事件,比如说10,5 5,3 等,第二个参数是skip,表示跳跃2个事件,来选取,所以是3组窗口,里面是 (10,5)(3,2)(1,0)

    输出:

    2018-04-27 14:06:08.703 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :我被2个打印一次 = 15
    2018-04-27 14:06:08.707 INFO [#][#] <main> com.dzy.learn.other.NormalTest :我被2个打印一次 = 5
    2018-04-27 14:06:08.707 INFO [#][#] <main> com.dzy.learn.other.NormalTest :我被2个打印一次 = 1
    window(long timespan, TimeUnit unit)
    CountDownLatch countDownLatch = new CountDownLatch(1);
    Observable inputEventStream = Observable.create(new Observable.OnSubscribe<Object>() {
    @Override
    public void call(Subscriber<? super Object> subscriber) {
    subscriber.onNext("我是生产者.........");
    }
    });
    inputEventStream.window(1000,TimeUnit.MILLISECONDS).subscribe(new Action1() {
    @Override
    public void call(Object o) {
    Calendar calendar = Calendar.getInstance();
    int i = calendar.get(Calendar.SECOND);
    LOG.info("我会{}就被唤醒触发...",i);
    }
    });
    countDownLatch.await();

    输出:

    2018-04-27 14:26:18.721 INFO  [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会18就被唤醒触发...
    2018-04-27 14:26:19.722 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会19就被唤醒触发...
    2018-04-27 14:26:20.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会20就被唤醒触发...
    2018-04-27 14:26:21.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会21就被唤醒触发...
    2018-04-27 14:26:22.722 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会22就被唤醒触发...
    2018-04-27 14:26:23.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会23就被唤醒触发...
    2018-04-27 14:26:24.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会24就被唤醒触发...
    2018-04-27 14:26:25.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会25就被唤醒触发...
    .....
    ...
    ..

    这里用CountDownLatch 阻塞了主线程的关闭,如果不用锁,那么主线程关闭了之后,你就看不到定时输出了。

    第二个demo,用到了window另外的一个函数,第一个参数是缓存在这个window的间隔时间,第二个参数是时间单位 , 1s内收到的所有的生产消息都会缓存到window里面,然后统一发出给订阅者。就好像一个时间轴上面,有个窗子在收集数据,1s钟之后收集好了之后,就发送出去,然后到了第二个窗子,这就是Hystrix滑动窗口的精髓所在。

    学以致用

    /**
    * 两个数字相加,reduce,scan用
    */

    public static final Func2<Integer, Integer, Integer> PUBLIC_SUM =
    (integer, integer2) -> integer + integer2;

    public static final Func1<Observable<Integer>, Observable<Integer>> WINDOW_SUM =
    //跳过第一个数据,因为给了scan一个默认值0,这个值需要跳过,如果不设置就不需要跳过
    window -> window.scan(0, PUBLIC_SUM).skip(1);

    public static final Func1<Observable<Integer>, Observable<Integer>> INNER_BUCKET_SUM =
    integerObservable -> integerObservable.reduce(0, PUBLIC_SUM);

    @Test
    public void testWindowSlide() throws InterruptedException {
    CountDownLatch countDownLatch = new CountDownLatch(1);
    BehaviorSubject<Integer> behaviorSubject = BehaviorSubject.create();
    behaviorSubject
    // 1秒作为一个基本块,横向移动
    .window(1000, TimeUnit.MILLISECONDS)
    //将flatMap汇总平铺成一个事件,然后累加成一个Observable<Integer>对象,比如说1s内有10个对象,被累加起来
    .flatMap(INNER_BUCKET_SUM)
    //对这个对象2个发送,步长为1
    .window(2,1)
    //对窗口里面的进行求和,用的scan, 每次累加都会打印出来
    .flatMap(WINDOW_SUM)
    .subscribe((Integer integer) ->
    // 输出统计数据到日志
    LOG.info("[{}] call ...... {}",
    Thread.currentThread().getName(), integer));

    for (int i = 0; i < 1000; i++) {
    //200ms生产一个数据,
    behaviorSubject.onNext(i);
    LOG.info("i = {}" ,i);
    Thread.sleep(200);
    }
    countDownLatch.await();
    }

    输出:

    2018-04-27 15:46:06.547 INFO  [#][#] <main> com.dzy.learn.other.NormalTest :i = 0
    2018-04-27 15:46:06.756 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 1
    2018-04-27 15:46:07.010 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 2
    2018-04-27 15:46:07.211 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 3
    2018-04-27 15:46:07.411 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 4
    2018-04-27 15:46:07.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 10
    2018-04-27 15:46:07.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 10
    2018-04-27 15:46:07.611 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 5
    2018-04-27 15:46:07.811 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 6
    2018-04-27 15:46:08.011 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 7
    2018-04-27 15:46:08.211 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 8
    2018-04-27 15:46:08.411 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 9
    2018-04-27 15:46:08.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 45
    2018-04-27 15:46:08.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 35
    2018-04-27 15:46:08.611 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 10
    2018-04-27 15:46:08.811 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 11
    2018-04-27 15:46:09.011 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 12
    2018-04-27 15:46:09.211 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 13
    2018-04-27 15:46:09.411 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 14
    2018-04-27 15:46:09.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 95
    2018-04-27 15:46:09.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 60

    解析,第一个window产生了一个滑动窗口,每秒钟就会把生产者生产的消息累加起来,第二个window是积累2个对象,然后进行发送,每次跳一个数字,第二个window是建立在第一个windows累加之后的基础上的,可能有点难理解,我们来看第一个window产生的序列如下:

    0  10  35  60  85  ......

    有的同学可能会问,你怎么知道,我看的log日志,打印出来的序列是 10 10 、 45 35 、95 60 、 145 85 、因为这里用的scan,每次累加之后都会把源数打印一遍,所以是0 10 35 60 85 。第二个window就在这个基础上进行累加 0+10 10+35 35+60 60+85,这样就完成了一个滑动窗口的监控过程

    结语

    这里总结的也许不是最全的,也许不是最新的版本,但是是Hystrix中用到的,结合Hystrix进行针对性讲解,对Hystrix的理解更加深刻,如有错误,望加以斧正,谢谢。

  • 相关阅读:
    vue part1 基础
    【转载】NBU异机恢复oracle
    【转载】跨域请求
    [转载] django contenttypes
    rest_framework setting
    rest_framework 视图/路由/渲染器/认证授权/节流
    【转载整理】 mysql百万级数据库分页性能
    rest_framework 分页
    rest_framework 序列化
    django middleware
  • 原文地址:https://www.cnblogs.com/itar/p/9013697.html
Copyright © 2011-2022 走看看