赞
踩
首先感谢 诸葛老师分享
图1
首先调用findById方法 调用接口报错的话,会走降级的方法 findByIdFallback方法。如果commandKey是空默认是类名。还可以配置线程池参数,目的是线程间的隔离。熔断, 降级
图2
图3
图4
图5
这个方法 META-INF/spring.factories 目录下找到 的EnableCircuitBreaker 为key 对应的类HystrixCircuitBreakerConfiguration,然后把他加入到spring容器中。
图6
图7
图8
图9
这个类和最核心的流程没有关系。
图10
38 行HystrixCommandAspect ,看到这个注解我们想到的是HystrixCommand 注解和切面 图11;
图11
图12
当我们发现77行我们是不是清晰多了。
88行,拿我们切点要执行的方法 ;96行create()方法图12-0
当我们调用这个hystrixCommandAnnotationPointcut()方法时候,在这个方法的前后做横切。默认走的103行,这是一个命令模式执行我们的方法。
图12-0
最终会走到43行,创建了一个命令Command
图12-1
图12-2
图12-3
命令方式最重要的一个方法是run方法。
图13
默认走51行
图14
把HystrixInvokable类型转换成HystrixExecutable类型。
图15
图16
图17
看来用的响应式编程。简单来说,运用了大量的观察者模式,并且比观察者模式还要复杂。 observalble被观察者,observer观察者,当被观察者发生变化会通知观察者。既然明白了观察者和被观察者,那我们的上面的call方法 就是,就是一个一个观察者,每一个观察都有对应的一个动作。当被观察者发生变化后,执行这个动作。
图18
这个对象是一个被观察者。返回的是一个applyHystrixSemantics对象。图20
最终上面的方法都没有调用,最终执行的是454行。这个是被观察者,这个返回的就是我们的观察者
485行. applyHystrixSemantics 这个对象真正是什么413行。
当terminate这个事件发生的时候,触发这个terminateCommandCleanup这个观察者事件。当这个事件doOnUnsubscribe方法时候,会触发unsubscribeCommandCleanup这个方法。 现在被观察者只是注册,并没有 调用。 这个afterCache从哪里来的呢,506行。hystrixObservable 这个对象从485行过来的。
图19
第一个观察者;
第二个观察者;
第三个观察者;
图20
523行看我们的熔断器是否能开启,图21 ,如果是关闭走的是降级逻辑,
如果打开走降级逻辑。图22;判断信号量如果够用的话执行这个逻辑。信号量不够的话就会降级。可以这样理解信号量是一个计数器,假如这个基数器是10,有一个命令来执行基数器加1,来10个命令来执行就是10,假如11个命令来了,信号量就是11了,这个时候判断这个时候信号量是不是超过了10,超过了直接拒绝,走降级逻辑。524行获取信号量。542行,如果没有配置信号量 542行,返回的是true.
又绑定了一组观察者和被观察者。
图19-0
首先判断配置文件里有没有配置信号量,线程隔离信号量的配置。如果没有配置就返回一个空的信号量。
图19-1
图19-2
最终看return方法。判断是否要执行超时逻辑。635行。636行执行我们的特定的隔离方法法。
图19-3
获取
649行从配置文件中获取线程的隔离的策略。
680行 真正调用run方法。
711行,线程真正隔离。只要我们能够找到线程池在什么地方初始化就能找到相关问题。 线程池配置图19-7 。
图19-4
图19-5
重新调到run方法。
图19-6
图19-7
图21
从配置中获取s是否强制打开断路器, 如果为false会强制走我们的的短路逻辑 ,判断一下opend的值如果是-1也是没有打开的。
图19-8
线程池定义。
图19-9
图19-10
图19-11
注解的信息
线程池的大小都是放meaHolder中的。joninPoint切点的注解的信息,元注解的信息。
metaHoder是什么呢?
buiilder是什么
builid什么
调用this后。 commandPropertiesDefaults 通过配置获取线程池信息。那setter是什么往上找
先从缓存中获取。 key 就是commandkey个方法对应一个线程池。 如果再两个方法上标注相同的commandkey那么这两个方法就会用共同的线程池。如果在两个方法中标注不同的commandkey 就会用不同的线程池。
图19-12
图19-13
到这里最后 如果线程池超出,走拒绝策略,走降级逻辑。
图22
图23
855行执行降级的逻辑。
图24
图25
返回配置的fallback方法。使用反射调用的方法
图26
图27
图28
run方法就是我们正常执行方法。也是利用反射拿command命令,也就是方法名称去执行真是的方法。
图29
熔断器默认是关闭的。 如果失败调用的达到了阀值,比如调用10次,其中有5次以上失败了。熔断器熔断的阀值是50%。熔断器打开以后,所有的请求都没有办法访问了。直接降级了。熔断器还有一个半开的概念,熔断器有一个熔断器时间窗,默认熔断器的时间窗是10s,如果在熔断器刚刚打开到10s之间 不管来多少请求都是没有办法访问的。但是过了这个熔断器的时间窗口后,熔断器会变成半开状态,只要来了一个请求,容器会试探的让他执行一次,如果这次请求执行成功了,熔断器关闭;如果失败了,熔断器又被打开,又要经历一个熔断期间窗口。
图30
图31
图32
图33
图34
断路器没有打开的情况:
如果熔断器打开走降级的逻辑。
图35
图36
看一下调用这个方法的地方。
图37
在往上找到调用他的方法;
图38
在往上找到调用他的方法;
图39
图40
是否配置了断路器,如果配置了走短路器逻辑。如果没有配置返回一个空的断路器。
图41
circuitBreakersBycommand 的key是commandKey,也就是这个commandKey不单对应一个短路器,他还对应了一个线程池。换句话说就是一个方法可以对应一个断路器,一个断路器也可以对应多个方法类似上面讲的线程.101行,初始化短路器,
图42
图43
时间窗口我们可以简单的理解为一个时间段,在一个时间段,9点到9点10分这个时间段调用10次其中有5次调用失败那么熔断器就会打开。当我们9点10分调用一个接口的时候,我们往前推10分钟 就是9点,看看在这个10分钟内调用的错误率是不是50%都失败了,这个配置metrics.rollingStats.timeInMillisenconds(时间窗口总大小)。问题来了,如果9点11分调用,那么统计的时间段应该是9点01分到9点11分的时间段。开始时间往后错1分钟。也就是说这个时间窗口是滑动的,每过1分钟,就会向后滑动一分钟。
判断请求的总次数是不是小于circuitBreaker.requestVolumeThreshold,滑动窗口触发熔断的最小请求数;代码跳过不做任何处理。
判断如果错误率小于配置文件的错误率,代码跳过不做任何处理。
如果上面两种情况都不满足直接打开。打开的时间circuitOpened设置值。
metrics.rollingStats.numBuckets 滑动窗口的份数(如果没有配置默认是10):Hystrix会在一个滑动窗口的时间段内,假设是10s分成10分,每一份就是1秒。然后统计每1一份内调用的成功的次数,失败的次数,超时的次数,拒绝的次数。把这些值分别储存起来。最终统计的错误率,每一秒(失败的次数+超时的次数+拒绝的次数) +++ 加10次,除以,10秒内调用次数的综合算出来的,错误率。这个错误率会和circuitBreaker.errorThresholdPercentage比较。 这种滑动窗口也可以用作接口限流。redis时间段的限流。从我这次调用过去的10秒流量的一个大小来限制;circuitBreaker.requestVolumeThreshold。滑动窗口触发熔断的最小请求数。如果滑动窗口时间内请求数只有19个,及时19个请求全部失败,也不会熔断,因为没有到达最小熔断数。如果到达20.有19个全部失败,超过了50% 就应该熔断了。为什么这样设计呢,这就是统计学的问题。数量太小不值当的统计呗。
图44。
滑动窗口次数统计的类。HealthCounts类的数据从哪里来呢,图49
图45
熔断器的状态。
图46
图47
判断是否强制打开或强制关闭断路器,circuitOpened 存短路器打开的时间。-1是断路器默认的值。如果是等于-1肯定是关闭的,直接返回true; 275行如果半开状态返回ture。 返回ture就会执行正常逻辑。返回false才会走降级逻辑。
图48
sleepWindowInMilliseconds 为熔断后多长时间放一些请求试探。默认是5秒。 如果 当前时间>熔断后打开的时间+熔断后多长时间后试探;
为半开状态。例如当前时间(16s)> 熔断器打开的时间是(10s)+ 熔断后多长时间试探(5s);275行改成半开状态。
图49
每次调用的结果,无论是成功,失败,异常,熔断器是否打开都会上传到metrics。如果metirics 会把最终的结果放在HealthCounts类里。
图50
markOnCompleted 注册的事件。关注一下重点行596行。上报数据到 metirics图51
643行当我们执行完成时候需要调用doOnCompleted(markOnCompleted)方法。我们看下这个方法markOnCompleted注册的事件;
图51
方法正常执行关闭熔断器,熔断器打开的时间设置为-1。metrics 做一些上传工作。
图52
最终把数据存到healthCounts中。清空数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。