Hystrix面试 - 深入 Hystrix 执行时内部原理
Hystrix面试 - 深入 Hystrix 执行时内部原理
前面我们了解了 Hystrix 最基本的支持高可用的技术:资源隔离 + 限流。
- 创建 command;
- 执行这个 command;
- 配置这个 command 对应的 group 和线程池。
这里,我们要讲一下,你开始执行这个 command,调用了这个 command 的 execute() 方法之后,Hystrix 底层的执行流程和步骤以及原理是什么。
在讲解这个流程的过程中,我会带出来 Hystrix 其他的一些核心以及重要的功能。
这里是整个 8 大步骤的流程图,我会对每个步骤进行细致的讲解。学习的过程中,对照着这个流程图,相信思路会比较清晰。
步骤一:创建 command
一个 HystrixCommand 或 HystrixObservableCommand 对象,代表了对某个依赖服务发起的一次请求或者调用。创建的时候,可以在构造函数中传入任何需要的参数。
- HystrixCommand 主要用于仅仅会返回一个结果的调用。
- HystrixObservableCommand 主要用于可能会返回多条结果的调用。
// 创建 HystrixCommand
HystrixCommand hystrixCommand = new HystrixCommand(arg1, arg2);// 创建 HystrixObservableCommand
HystrixObservableCommand hystrixObservableCommand = new HystrixObservableCommand(arg1, arg2);
步骤二:调用 command 执行方法
执行 command,就可以发起一次对依赖服务的调用。
要执行 command,可以在 4 个方法中选择其中的一个:execute()、queue()、observe()、toObservable()。
其中 execute() 和 queue() 方法仅仅对 HystrixCommand 适用。
- execute():调用后直接 block 住,属于同步调用,直到依赖服务返回单条结果,或者抛出异常。
- queue():返回一个 Future,属于异步调用,后面可以通过 Future 获取单条结果。
- observe():订阅一个 Observable 对象,Observable 代表的是依赖服务返回的结果,获取到一个那个代表结果的 Observable 对象的拷贝对象。
- toObservable():返回一个 Observable 对象,如果我们订阅这个对象,就会执行 command 并且获取返回结果。
K value = hystrixCommand.execute();
Future<K> fValue = hystrixCommand.queue();
Observable<K> oValue = hystrixObservableCommand.observe();
Observable<K> toOValue = hystrixObservableCommand.toObservable();
execute() 实际上会调用 queue().get() 方法,可以看一下 Hystrix 源码。
public R execute() {try {return queue().get();} catch (Exception e) {throw Exceptions.sneakyThrow(decomposeException(e));}
}
而在 queue() 方法中,会调用 toObservable().toBlocking().toFuture()。
final Future<R> delegate = toObservable().toBlocking().toFuture();
也就是说,先通过 toObservable() 获得 Future 对象,然后调用 Future 的 get() 方法。那么,其实无论是哪种方式执行 command,最终都是依赖于 toObservable() 去执行的。
步骤三:检查是否开启缓存
从这一步开始,就进入到 Hystrix 底层运行原理啦,看一下 Hystrix 一些更高级的功能和特性。
如果这个 command 开启了请求缓存 Request Cache,而且这个调用的结果在缓存中存在,那么直接从缓存中返回结果。否则,继续往后的步骤。
步骤四:检查是否开启了断路器
检查这个 command 对应的依赖服务是否开启了断路器。如果断路器被打开了,那么 Hystrix 就不会执行这个 command,而是直接去执行 fallback 降级机制,返回降级结果。
步骤五:检查线程池/队列/信号量是否已满
如果这个 command 线程池和队列已满,或者 semaphore 信号量已满,那么也不会执行 command,而是直接去调用 fallback 降级机制,同时发送 reject 信息给断路器统计。
步骤六:执行 command
调用 HystrixObservableCommand 对象的 construct() 方法,或者 HystrixCommand 的 run() 方法来实际执行这个 command。
- HystrixCommand.run() 返回单条结果,或者抛出异常。
// 通过command执行,获取最新一条商品数据
ProductInfo productInfo = getProductInfoCommand.execute();
- HystrixObservableCommand.construct() 返回一个 Observable 对象,可以获取多条结果。
Observable<ProductInfo> observable = getProductInfosCommand.observe();// 订阅获取多条结果
observable.subscribe(new Observer<ProductInfo>() {@Overridepublic void onCompleted() {System.out.println("获取完了所有的商品数据");}@Overridepublic void onError(Throwable e) {e.printStackTrace();}/*** 获取完一条数据,就回调一次这个方法* @param productInfo*/@Overridepublic void onNext(ProductInfo productInfo) {System.out.println(productInfo);}
});
如果是采用线程池方式,并且 HystrixCommand.run() 或者 HystrixObservableCommand.construct() 的执行时间超过了 timeout 时长的话,那么 command 所在的线程会抛出一个 TimeoutException,这时会执行 fallback 降级机制,不会去管 run() 或 construct() 返回的值了。另一种情况,如果 command 执行出错抛出了其它异常,那么也会走 fallback 降级。这两种情况下,Hystrix 都会发送异常事件给断路器统计。
注意,我们是不可能终止掉一个调用严重延迟的依赖服务的线程的,只能说给你抛出来一个 TimeoutException。
如果没有 timeout,也正常执行的话,那么调用线程就会拿到一些调用依赖服务获取到的结果,然后 Hystrix 也会做一些 logging 记录和 metric 度量统计。
步骤七:断路健康检查
Hystrix 会把每一个依赖服务的调用成功、失败、Reject、Timeout 等事件发送给 circuit breaker 断路器。断路器就会对这些事件的次数进行统计,根据异常事件发生的比例来决定是否要进行断路(熔断)。如果打开了断路器,那么在接下来一段时间内,会直接断路,返回降级结果。
如果在之后,断路器尝试执行 command,调用没有出错,返回了正常结果,那么 Hystrix 就会把断路器关闭。
步骤八:调用 fallback 降级机制
在以下几种情况中,Hystrix 会调用 fallback 降级机制。
- 断路器处于打开状态;
- 线程池/队列/semaphore满了;
- command 执行超时;
- run() 或者 construct() 抛出异常。
一般在降级机制中,都建议给出一些默认的返回值,比如静态的一些代码逻辑,或者从内存中的缓存中提取一些数据,在这里尽量不要再进行网络请求了。
在降级中,如果一定要进行网络调用的话,也应该将那个调用放在一个 HystrixCommand 中进行隔离。
- HystrixCommand 中,实现 getFallback() 方法,可以提供降级机制。
- HystrixObservableCommand 中,实现 resumeWithFallback() 方法,返回一个 Observable 对象,可以提供降级结果。
如果没有实现 fallback,或者 fallback 抛出了异常,Hystrix 会返回一个 Observable,但是不会返回任何数据。
不同的 command 执行方式,其 fallback 为空或者异常时的返回结果不同。
- 对于 execute(),直接抛出异常。
- 对于 queue(),返回一个 Future,调用 get() 时抛出异常。
- 对于 observe(),返回一个 Observable 对象,但是调用 subscribe() 方法订阅它时,立即抛出调用者的 onError() 方法。
- 对于 toObservable(),返回一个 Observable 对象,但是调用 subscribe() 方法订阅它时,立即抛出调用者的 onError() 方法。
不同的执行方式
- execute(),获取一个 Future.get(),然后拿到单个结果。
- queue(),返回一个 Future。
- observe(),立即订阅 Observable,然后启动 8 大执行步骤,返回一个拷贝的 Observable,订阅时立即回调给你结果。
- toObservable(),返回一个原始的 Observable,必须手动订阅才会去执行 8 大步骤。
转载来源:https://github.com/doocs/advanced-java/blob/master/docs/high-availability/hystrix-process.md
Hystrix面试 - 深入 Hystrix 执行时内部原理相关推荐
- Hystrix(6) 深入 Hystrix 执行时内部原理
深入 Hystrix 执行时内部原理 前面我们了解了 Hystrix 最基本的支持高可用的技术:资源隔离 + 限流. 创建 command: 执行这个 command: 配置这个 command 对应 ...
- Hystrix面试 - 深入 Hystrix 断路器执行原理
Hystrix面试 - 深入 Hystrix 断路器执行原理 RequestVolumeThreshold HystrixCommandProperties.Setter().withCircuitB ...
- Hystrix面试 - 深入 Hystrix 线程池隔离与接口限流
Hystrix面试 - 深入 Hystrix 线程池隔离与接口限流 前面讲了 Hystrix 的 request cache 请求缓存.fallback 优雅降级.circuit breaker 断路 ...
- Hystrix面试 - 基于 Hystrix 信号量机制实现资源隔离
Hystrix面试 - 基于 Hystrix 信号量机制实现资源隔离 Hystrix 里面核心的一项功能,其实就是所谓的资源隔离,要解决的最最核心的问题,就是将多个依赖服务的调用分别隔离到各自的资源池 ...
- Hystrix面试 - 基于 Hystrix 线程池技术实现资源隔离
Hystrix面试 - 基于 Hystrix 线程池技术实现资源隔离 上一讲提到,如果从 Nginx 开始,缓存都失效了,Nginx 会直接通过缓存服务调用商品服务获取最新商品数据(我们基于电商项目做 ...
- Hystrix面试 - 用 Hystrix 构建高可用服务架构
Hystrix面试 - 用 Hystrix 构建高可用服务架构 Hystrix 是什么? 在分布式系统中,每个服务都可能会调用很多其他服务,被调用的那些服务就是依赖服务,有的时候某些依赖服务出现故障也 ...
- Hystrix面试 - Hystrix 隔离策略细粒度控制
Hystrix面试 - Hystrix 隔离策略细粒度控制 Hystrix 实现资源隔离,有两种策略: 线程池隔离 信号量隔离 对资源隔离这一块东西,其实可以做一定细粒度的一些控制. executio ...
- Hystrix面试 - 基于 timeout 机制为服务接口调用超时提供安全保护
Hystrix面试 - 基于 timeout 机制为服务接口调用超时提供安全保护 一般来说,在调用依赖服务的接口的时候,比较常见的一个问题就是超时.超时是在一个复杂的分布式系统中,导致系统不稳定,或者 ...
- Hystrix php,详解 hystrix-go 使用与原理
下面由golang教程栏目给大家介绍关于golang封装一个bash函数,用于执行bash命令析,希望对需要的朋友有所帮助! 开篇 这周在看内部一个熔断限流包时,发现它是基于一个开源项目 hystri ...
最新文章
- LeetCode 860.柠檬水找零(C++)
- spring 读取配置文件的优先级
- SQL 2005/2008 清空收缩日志
- Cocos2D v2.0至v3.x简洁转换指南(一)
- mailto 附带附件_我和我的朋友如何将附带项目发展为每月$ 17,000的业务
- 程序员年薪高达40万,为什么有很多程序员单身?看看网友怎么说!
- 16小时31分12秒!2019天猫双11成交额超2135亿元,超越2018年全天成交额
- 悟透delphi 第五章 包
- 从客户端中检测到有潜在危险的 Request.Form 值。
- 我的vs2010扩展备忘.jpg
- 【MySql】Navicat Premium 15 无限试用脚本
- WiFi共享大师 去广告
- 使用matlab进行简单图像处理
- 高薪职位怎么找?你们来学学这3招
- 鼠标手势插件--smartUp
- [SCOI2009]windy数
- bon app android,Bon App!
- 多签名基础——General forking lemma(分叉引理)
- 一个刚毕业的大学生在一个陌生的城市如何租房?
- oracle索引管理
热门文章
- 开源ckplayer 网页播放器, 跨平台(html5, mobile),flv, f4v, mp4, rtmp协议. webm, ogg, m3u8 !...
- oracle execute immediate用法
- MySQL—delete和truncate的区别
- 【设计模式】设计模式C++编程实现之单例模式(Singleton Pattern)
- dj鲜生-35-设置django的session使用redis来存储
- python-面向对向-静态方法的继承-父类中的super方法
- dj电商-需求分析-购物车模块与订单模块
- django-模型类管理器
- jquery-窗口滚动事件-属性操作
- kubernetes日志采集与解析