Hystrix 源码解析 —— 命令执行(一)之正常执行逻辑
来源:互联网 发布:电影人工智能观后感 编辑:程序博客网 时间:2024/06/05 08:02
摘要: 原创出处 http://www.iocoder.cn/Hystrix/command-execute-first-run/ 「芋道源码」欢迎转载,保留摘要,谢谢!
本文主要基于 Hystrix 1.5.X 版本
- 1. 概述
- 2. #applyHystrixSemantics(…)
- 3. TryableSemaphore
- 4. #executeCommandAndObserve(…)
- 5. #executeCommandWithSpecifiedIsolation(…)
- 6. #getUserExecutionObservable(…)
- 7. #getExecutionObservable()
- 8. CommandState
- 9. ThreadState
- 666. 彩蛋
1. 概述
本文主要分享 Hystrix 命令执行(一)之正常执行逻辑。
建议 :对 RxJava 已经有一定的了解的基础上阅读本文。
Hystrix 执行命令整体流程如下图:
FROM 《【翻译】Hystrix文档-实现原理》「流程图」
- 红框 :Hystrix 命令执行的过程。
- 蓝圈 :本文分享的部分 —— 正常执行逻辑。
推荐 Spring Cloud 书籍:
- 请支持正版。下载盗版,等于主动编写低级 BUG 。
- 程序猿DD —— 《Spring Cloud微服务实战》
- 周立 —— 《Spring Cloud与Docker微服务架构实战》
- 两书齐买,京东包邮。
2. #applyHystrixSemantics(…)
在 《Hystrix 源码解析 —— 执行结果缓存》 里,我们看到 #toObservable()
方法里的第 11 至 19 行,当缓存特性未开启,或者缓存未命中时,使用 applyHystrixSemantics
传入 Observable#defer(...)
方法,声明执行命令的 Observable。
创建 applyHystrixSemantics
变量,代码如下 :
- 第 5 至 7 行 :当
commandState
处于UNSUBSCRIBED
时,不执行命令。 - 第 9 行 :调用
#applyHystrixSemantics(...)
方法,获得执行 Observable 。
#applyHystrixSemantics(...)
方法,代码如下 :
- 第 5 行 :TODO 【2003】【HOOK】
- 第 8 行 :TODO 【2012】【链路健康度】
- 第 10 行 :调用
#getExecutionSemaphore()
方法,获得信号量( TryableSemaphore )对象,在 「3. TryableSemaphore」 详细解析。 - 第 13 至 21 行 :信号量释放 Action ,用于下面【执行命令 Observable】的
#doOnTerminate(Action)
和#doOnUnsubscribe(Action)
方法( 见第 41 至 42 行 )。 - 第 24 至 29 行 :TODO 【2011】【Hystrix 事件机制】
- 第 32 行 :调用
TryableSemaphore#tryAcquire()
方法,信号量( TryableSemaphore )使用成功,在 「3. TryableSemaphore」 详细解析。 - 第 36 行 :标记
executionResult
的调用开始时间。 - 第 39 行 :调用
#executeCommandAndObserve()
方法,获得【执行命令 Observable】。在 「4. #executeCommandAndObserve(…)」 详细解析。 - 第 43 至 45 行 :若发生异常,调用
Observable#error(Exception)
方法返回 Observable 。 - 第 46 至 48 行 :信号量( TryableSemaphore )使用失败,调用
#handleSemaphoreRejectionViaFallback()
方法,处理信号量拒绝的失败回退逻辑,在 《Hystrix 源码解析 —— 命令执行(四)之失败回退逻辑》 详细解析。 - 第 49 至 51 行 :链路处于熔断状态,调用
#handleShortCircuitViaFallback()
方法,处理链路熔断的失败回退逻辑,在 《Hystrix 源码解析 —— 命令执行(四)之失败回退逻辑》 详细解析。
3. TryableSemaphore
com.netflix.hystrix.AbstractCommand.TryableSemaphore
,Hystrix 定义的信号量接口。代码如下 :
- 从 API 上,Java 自带的
java.util.concurrent.Semaphore
都能满足,为什么不使用它呢?继续一起往下看。
TryableSemaphore 共有两个子类实现 :
- TryableSemaphoreNoOp
- TryableSemaphoreActual
3.1 TryableSemaphoreNoOp
com.netflix.hystrix.AbstractCommand.TryableSemaphoreNoOp
,无操作的信号量。代码如下 :
- 从实现上看,
#tryAcquire()
方法,每次都返回的是true
;#release()
方法,无任何操作。这个是为什么?在 Hystrix 里提供了两种执行隔离策略 :Thread
,该方式不使用信号量,因此使用 TryableSemaphoreNoOp ,这样每次调用#tryAcquire()
都能返回true
。在 《Hystrix 源码解析 —— 命令执行(二)之执行隔离策略》 详细解析该方式。Semaphore
,该方式使用信号量,因此使用 TryableSemaphoreActual ,这样每次调用#tryAcquire()
根据情况返回true / false
。在 「3.2 TryableSemaphoreActual」 详细解析。
3.2 TryableSemaphoreActual
com.netflix.hystrix.AbstractCommand.TryableSemaphoreActual
,真正的的信号量实现。不过实际上,TryableSemaphoreActual 更加像一个计数器。代码如下 :
numberOfPermits
属性,信号量上限。com.netflix.hystrix.strategy.properties.HystrixProperty
是一个接口,当其使用类似com.netflix.hystrix.strategy.properties.archaius.IntegerDynamicProperty
动态属性的实现时,可以实现动态调整信号量的上限,这就是上文提到的为什么不使用java.util.concurrent.Semaphore
的原因之一。count
属性,信号量使用数量。��,这是为什么说 TryableSemaphoreActual 更加像一个计数器 的原因。- 另一个不使用
java.util.concurrent.Semaphore
的原因,TryableSemaphoreActual 无阻塞获取信号量的需求,使用 AtomicInteger 可以达到更轻量级的实现。
3.3 #getExecutionSemaphore()
调用 #getExecutionSemaphore()
方法,获得信号量对象,代码如下 :
- 根据执行隔离策略不同获取不同的信号量实现 :
Thread
,该方式不使用信号量,因此使用 TryableSemaphoreNoOp 。Semaphore
,该方式使用信号量,因此使用 TryableSemaphoreActual 。- 相同的
commandKey
,使用相同的 TryableSemaphoreActual 。
- 相同的
4. #executeCommandAndObserve(…)
调用 #executeCommandAndObserve(...)
方法,获得【执行命令 Observable】。代码如下 :
- 第 3 行 :TODO 【2012】【请求上下文】
- 第 6 至 21 行 :TODO 【2007】【executionResult】用途
- 第 24 至 35 行 :TODO 【2007】【executionResult】用途
- 第 38 至 62 行 :失败回退逻辑 Func1 ,在 《Hystrix 源码解析 —— 请求执行(四)之失败回退逻辑》 详细解析。
- 第 65 至 70 行 :TODO 【2012】【请求上下文】
- 第 72 至 78 行 :调用
#executeCommandWithSpecifiedIsolation(...)
方法,获得【执行命令 Observable】,在 「5. #executeCommandWithSpecifiedIsolation(…)」 详细解析。- 若执行命令超时特性开启,调用
Observable#lift(HystrixObservableTimeoutOperator)
方法,实现执行命令超时功能。在 《Hystrix 源码解析 —— 命令执行(三)之执行超时》 详细解析。
- 若执行命令超时特性开启,调用
- 第 80 至 83 行 :返回【执行命令 Observable】。
5. #executeCommandWithSpecifiedIsolation(…)
调用 #executeCommandWithSpecifiedIsolation(...)
方法,获得【执行命令 Observable】。代码如下 :
- 根据执行隔离策略不同,创建不同的【执行命令 Observable】。仔细对比下,大体逻辑都是相同的,差别在于执行隔离策略为
Thread
时,使用 RxJava Scheduler 以及对线程的处理。 第 2 至 85 行 :执行隔离策略为
Thread
:- 第 9 行 :标记
executionResult
执行已发生。 - 第 12 至 14 行 :设置
commandState
为USER_CODE_EXECUTED
。若设置失败,调用Observable#error(Exception)
方法返回 Observable 。 - 第 17 行 :TODO 【2002】【metrics】
- 第 20 至 24 行 :TODO 【2009】【执行超时】
- 第 27 行 :设置
threadState
为ThreadState.STARTED
成功。- 第 30 至 31 行 :TODO 【2002】【metrics】
- 第 35 行 :TODO 【2010】【endCurrentThreadExecutingCommand】
- 第 38 行 :标记
executionResult
使用线程执行。 - 第 44 至 46 行 :TODO 【2003】【HOOK】
- 第 49 行 :调用
#getUserExecutionObservable(...)
方法,创建【执行命令 Observable】。 - 第 50 至 52 行 :若发生异常,调用
Observable#error(Exception)
方法返回 Observable 。
- 第 53 至 56 行 :设置
threadState
为ThreadState.STARTED
失败,执行命令此时已经被取消,调用Observable#empty()
方法返回 Observable 。 - 第 58 至 68 行 :调用
Observable#doOnTerminate(...)
方法,添加 Action0 。#handleThreadEnd(...)
方法,点击 链接 查看。 - 第 69 至 79 行 :调用
Observable#doOnUnsubscribe(...)
方法,添加 Action0 。 - 第 80 至 85 行 :调用
Observable#subscribeOn(Scheduler)
方法,指定 Observable 自身在哪个调度器上执行。- RxJava Scheduler ,在 《RxJava 源码解析 —— Scheduler》 有详细解析。
Observable#subscribeOn(Scheduler)
,在 《RxJava 源码解析 —— Observable#subscribeOn(Scheduler)》 有详细解析。- 调用
ThreadPool#getScheduler(Func0<Boolean>)
方法,获得 Hystrix 自定义实现的 RxJava Scheduler ,在 《Hystrix 源码解析 —— 命令执行(二)之执行隔离策略》 详细解析。
- 第 9 行 :标记
第 86 至 118 行 :执行隔离策略为
SEMAPHORE
:- 第 91 行 :[ 与第 9 行相同 ]。
- 第 94 至 96 行 :[ 与第 12 至 14行相同 ]。
- 第 99 行 :[ 与第 17 行类似 ]。
- 第 104 行 :[ 与第 35 行相同 ]。
- 第 107 至 108 行 :[ 与第 45 至 46 行相同 ]。
- 第 111 行 :[ 与第 49 行相同 ]。
- 第 112 至 115 行 :[ 与第 50 至 52 行相同 ]。
6. #getUserExecutionObservable(…)
调用 #getUserExecutionObservable(...)
方法,创建【执行命令 Observable】。代码如下 :
第 5 行 :调用
#getExecutionObservable()
方法,创建【执行命令 Observable】。#getExecutionObservable()
是个抽象方法,代码如下 :- HystrixCommand 实现了该方法,在 「7. #getExecutionObservable」 详细解析。
第 6 至 10 行 :若发生异常,调用
Observable#error(Exception)
方法返回 Observable 。- 第 12 至 14 行 :返回【执行命令 Observable】。
- 第 13 行 :TODO 【2003】【HOOK】
7. #getExecutionObservable()
调用 HystrixCommand#getExecutionObservable()
方法,创建【执行命令 Observable】。代码如下 :
- 第 3 至 11 行 :调用
Observable#defer(Func0<Observable<R>)
方法,创建【执行命令 Observable】。- 第 7 行 :调用
#run()
方法,运行正常执逻辑。通过Observable#just(...)
方法,返回创建【执行命令 Observable】。
- 第 7 行 :调用
- 第 12 至 19 行 :调用
#doOnSubscribe(...)
方法,添加 Action 。该操作记录执行线程(executionThread
) 。executionThread
用于HystrixCommand#queue()
方法,返回的 Future 结果,可以调用Future#cancel(Boolean)
方法,点击 链接 查看该方法。 - 第 22 行 :
#run()
抽象方法,实现该方法,运行正常执逻辑。
8. CommandState
com.netflix.hystrix.AbstractCommand.CommandState
,命令状态,代码如下 :
状态变迁如下图 :
9. ThreadState
com.netflix.hystrix.AbstractCommand.ThreadState
,线程状态,代码如下 :
状态变迁如下图 :
- 熔断器 Hystrix 源码解析 —— 命令执行(一)之正常执行逻辑
- Hystrix 源码解析 —— 命令执行(一)之正常执行逻辑
- 熔断器 Hystrix 源码解析 —— 命令执行(二)之执行隔离策略
- Hystrix 源码解析 —— 命令执行(二)之执行隔离策略
- Hystrix 源码解析 —— 命令执行(三)之执行超时
- 熔断器 Hystrix 源码解析 —— 命令执行(三)之执行超时
- Hystrix 源码解析 —— 请求执行(四)之失败回退逻辑
- 熔断器 Hystrix 源码解析 —— 请求执行(四)之失败回退逻辑
- 熔断器 Hystrix 源码解析 —— 执行命令方式
- Hystrix 源码解析 —— 命令合并执行
- Hystrix 源码解析 —— 执行命令方式
- 熔断器 Hystrix 源码解析 —— 执行结果缓存
- Hystrix 源码解析 —— 执行结果缓存
- UiAutomator系列——Appium Android Bootstrap源码分析之命令解析执行(008)
- Appium Android Bootstrap源码分析之命令解析执行
- Appium Android Bootstrap源码分析之命令解析执行
- Hystrix 源码解析 —— 断路器 HystrixCircuitBreaker
- WINVNC分析(一)——源码执行流程
- 1.1 学习之初;1.2 约定;1.3 认识Linux;1.4 创建虚拟机;1.5安装centos7
- linux内核模块之Makefile模板
- Java多线程
- Team_Codeforces_231A
- 右值引用
- Hystrix 源码解析 —— 命令执行(一)之正常执行逻辑
- 多线程互斥量Mutex的使用
- HTML5:理解head
- 【分布式架构】企业级分布式应用服务EDAS使用攻略(上篇)
- Kotlin回调的使用以及let、also、with、run、apply函数的用法
- windows adb不识别(VID PID更改)
- 【Python小游戏】俄罗斯方块
- ios 音乐跳动动画-CAReplicatorLayer
- Top 9 questions about Java Maps (关于java map集合的前九个问题)