通过Netflix Hystrix官方公布的流程图,我们来了解一下Hystrix的工作流程

1. 创建HystrixCommand对象或者HystrixObservableCommand对象
首先, 创建一个HystrixCommand对象或者HystrixObservableCommand对象用来表示对依赖服务的操作请求, 同时传递所有需要的参数, 它采用了命令模式来实现对服务调用操作的封装, 这两个Command对象分别针对不同的应用场景.
-
HystrixCommand: 依赖服务每次返回单一的回应。
HystrixCommand command = new HystrixCommand(arg1, arg2);
-
HystrixObservableCommand: 若期望依赖服务返回一个Observable, 并应用Observer模式监听依赖服务的回应, 用在依赖的服务返回多个操作结果的时候.
HystrixObservableCommand command = new HystrixObservableCommand(arg1, arg2);
1.1 命令模式
将请求封装成对象, 使用不同的请求,队列或者日志请求来参数化其他对象, 就是命令模式. 命令模式也可以支持撤销操作. 当需要将请求的对象和执行请求的对象解耦的时候, 可以考虑使用命令模式.
1.2 命令模式的要点
- 命令模式将发出请求的对象和执行请求的对象解耦;
- 在被解耦的两者之间是通过命令对象进行沟通的, 命令对象封装了接收者和一个或一组动作;
- 调用者通过调用命令对象的
execute()方法发出请求, 这会使得接收者的动作被调用; - 调用者可以接受命令当作参数, 甚至在运行时动态地进行;
- 命令可以支持撤销, 做法是实现一个
undo()方法来回到execute()方法被执行前的状态;
2. 调用Command的执行方法
执行Command就可以发起一次对依赖服务的调用.
要执行Command, 需要在4个方法中选择其中一个, 但主要是使用仅对HystrixCommand适用的两个:
-
execute(): 同步执行, 从依赖的服务返回一个单一的结果对象, 或者是在发生错误的时候抛出异常. -
queue(): 异步执行, 直接返回一个Future对象, 其中包含了服务执行结束时要返回的单一结果对象.
R value = command.execute();
Future<R> fValue = command.queue();
而另外两种执行方式, 适用于HystrixObservableCommand:
-
observe(): 订阅一个Observable对象,Observable代表的是依赖服务返回的结果, 获取到一个那个代表结果的Observable对象的拷贝对象, 是一个 hot observable; -
toObservable(): 返回一个Observable对象, 如果我们订阅这个对象, 就会执行command并且获取返回结果, 是一个 cold observable
Observable<R> ohValue = command.observe(); //hot observable
Observable<R> ocValue = command.toObservable(); //cold observable
execute()实际上会调用queue().get().queue(), 接着会调用toObservable().toBlocking().toFuture(), 也就是说, 无论是哪种执行command的方式, 最终都是依赖toObservable()去执行的.
3. 检查是否开启缓存
若当前命令的请求缓存功能(request cache)是被启用的, 并且该命令缓存命中, 那么缓存的结果会立即以Observable对象的形式返回.
4. 检查是否开启了短路器
在命令结果没有被缓存命中的时候, Hystrix会在执行命令前检查断路器是否为打开状态:
- 如果断路器是打开的, 那么
Hystrix不会执行命令, 而是转接到fallback处理逻辑(第8步). - 如果断路器是关闭的,
Hystrix会检查是否有可用资源来执行命令(第5步).
5. 检查线程池/队列/semaphore是否已经满了
如果command对应的线程池, 列队, semeaphore已经满了, 那么也不会执行command, 而是直接调用fallback降级机制.
6. 执行command
Hystrix会根据我们编写的方法来决定采取什么样的方式去请求依赖服务.
HystrixCommand.run()--返回单个响应或抛出异常.HystrixObservableCommand.construct()--返回Observable对象来发射多个结果, 或通过onError发送错误通知.
如果HystrixCommand.run()或HystrixObservableCommand.construct()的执行, 超过了timeout时长的话, 那么command所在的线程就会抛出一个TimeoutException.
如果timeout了, 也会去执行fallback降级机制, 而且就不会管run()或construct()返回的值了.
如果没有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()——成功时返回java.util.concurrent.Future, 但如果调用Future.get()将抛出异常 -
observe()——返回Observable对象, 当你订阅该Observable时, 将会立即终止并且调用订阅者的onError方法. -
toObservable()——同observe()
9. 返回成功的响应
当Hystrix命令执行成功后, 会将处理结果直接返回或是以Observable的形式返回, 具体怎么返回要根据执行命令的方式来区分, 下图是四种执行方式的依赖关系:
-
execute(), 获取一个Future.get(), 然后拿到单个结果; -
queue(), 返回一个Future; -
observer(), 立即订阅Observable, 然后启动8大执行步骤, 返回一个拷贝的Observable, 订阅时理解回调给你结果; -
toObservable(), 返回一个原始的Observable, 必须手动订阅才会去执行8大步骤.
参考文章:
1 https://www.jianshu.com/p/cd0d7ac31596
2 https://www.cnblogs.com/holly8/p/11226177.html
3 https://my.oschina.net/u/4006148/blog/3176044