【Hystrix技术指南】(5)Command创建和执行实现

简介: 【Hystrix技术指南】(5)Command创建和执行实现

创建流程


构建HystrixCommand或者HystrixObservableCommand对象


  • 使用Hystrix的第一步是创建一个HystrixCommand或者HystrixObservableCommand对象来表示你需要发给依赖服务的请求。


若只期望依赖服务每次返回单一的回应,按如下方式构造一个HystrixCommand即可


HystrixCommand command = new HystrixCommand(arg1, arg2);
复制代码



若期望依赖服务返回一个Observable,并应用『Observer』模式监听依赖服务的回应,可按如下方式构造一个HystrixObservableCommand

HystrixObservableCommand command = new HystrixObservableCommand(arg1, arg2);
复制代码



执行命令


Hystrix 命令提供四种方式(HystrixCommand支持所有四种方式,而HystrixObservableCommand仅支持后两种方式)来执行你包装的请求


  • execute()—— 阻塞,当依赖服务响应(或者抛出异常/超时)时,返回结果
  • queue()—— 返回Future对象,通过该对象异步得到返回结果
  • observe()—— 返回Observable对象,立即发出请求,在依赖服务响应(或者抛出异常/超时)时,通过注册的Subscriber得到返回结果
  • toObservable()—— 返回Observable对象,但只有在订阅该对象时,才会发出请求,然后在依赖服务响应(或者抛出异常/超时)时,通过注册的Subscriber得到返回结果


K value   = command.execute();
Future<K>     fValue  = command.queue();
 // hot observable(注:调用observe()方法时,请求立即发出)
Observable<K> ohValue = command.observe();
 // cold observable(注:只有在返回的ocValue上调用subscribe时,才会发出请求)
Observable<K> ocValue = command.toObservable();
复制代码


内部实现中


  • execute()是同步调用,内部会调用queue().get()方法
  • queue()内部会调用toObservable().toBlocking().toFuture()


HystrixCommand内部均通过一个Observable的实现来执行请求,即使这些命令本来是用来执行同步返回回应这样的简单逻辑。



1. 结果是否有缓存


如果请求结果缓存这个特性被启用,并且缓存命中,则缓存的回应会立即通过一个Observable对象的形式返回。


2. 请求线路是否是开路


  • 当执行一个命令时,Hystrix 会先检查熔断器状态,确定请求线路是否是开路
  • 如果请求线路是开路,Hystrix将不会执行这个命令,而是直接使用『失败回退逻辑』fallback



3. 线程池/请求队列/信号量占满时会发生什么


如果和当前需要执行的命令相关联的线程池和请求队列(或者信号量,如果不使用线程池),Hystrix 将不会执行这个命令,而是直接使用『失败回退逻辑』


使用HystrixObservableCommand.construct()还是HystrixCommand.run()

Hystrix将根据你使用类的不同,内部使用不同的方式来请求依赖服务:


  • HystrixCommand.run()—— 返回回应或者抛出异常


  • HystrixObservableCommand.construct()—— 返回Observable对象,并在回应到达时通知 observers,或者回调onError方法通知出现异常


若run()或者construct()方法耗时超过了给命令设置的超时阈值,执行请求的线程将抛出TimeoutException(若命令本身并不在其调用线程内执行,则单独的定时器线程会抛出该异常)。



在这种情况下,Hystrix将会执行失败回退逻辑,并且会忽略最终(若执行命令的线程没有被中断)返回的回应



若命令本身并不抛出异常,并正常返回回应,Hystrix在添加一些日志和监控数据采集之后,直接返回回应。


  • Hystrix 在使用run()方法时,Hystrix内部还是会生成一个Observable对象,并返回单个请求,产生一个onCompleted通知
  • 而在 Hystrix 使用construct()时,会直接返回由construct()产生的Observable对象



计算线路健康度


Hystrix会将请求成功,失败,被拒绝或超时信息报告给熔断器,熔断器维护一些用于统计数据用的计数器。


这些计数器产生的统计数据使得熔断器在特定的时刻,能短路某个依赖服务的后续请求,直到恢复期结束,若恢复期结束根据统计数据熔断器判定线路仍然未恢复健康,熔断器会再次关闭线路。




失败回退逻辑


当命令执行失败时,Hystrix 将会执行失败回退逻辑,失败原因可能是


  1. construct()或run()方法抛出异常HystrixBadRequestException除外
  2. 当线路是开路,导致命令被短路时
  3. 当命令对应的线程池或信号量被占满
  4. 执行操作超时!



回退具体介绍


  • 失败回退逻辑包含了通用的回应信息,这些回应从内存缓存中或者其他固定逻辑中得到,而不应有任何的网络依赖


  • 如果一定要在失败回退逻辑中包含网络请求,必须将这些网络请求包装在另一个HystrixCommand或HystrixObservableCommand中


  • 当使用HystrixCommand时,通过实现HystrixCommand.getFallback()返回失败回退时的回应。


  • 当使用HystrixObservableCommand时,通过实现HystrixObservableCommand.resumeWithFallback()返回 Observable 对象来通知 observers 失败回退时的回应。


  • 若失败回退方法返回回应,Hystrix会将这个回应返回给命令的调用者。


  • 若Hystrix内部调用HystrixCommand.getFallback()时,会产生一个Observable对象,并包装用户实现的getFallback()方法返回的回应;


  • 若 Hystrix内部调用HystrixObservableCommand.resumeWithFallback()时,会将用户实现的resumeWithFallback()返回的Observable对象直接返回。


  • 若你没有实现失败回退方法,或者失败回退方法抛出异常,Hystrix 内部还是会生成一个 Observable对象,但它不会产生任何回应,并通过onError通知立即中止请求


  • Hystrix默认会通过onError通知调用者发生了何种异常。你需要尽量避免失败回退方法执行失败,保持该方法尽可能的简单不易出错


  • 若失败回退方法执行失败,或者用户未提供失败回退方法,Hystrix会根据调用执行命令的方法的不同而产生不同的行为


  • execute()—— 抛出异常
  • queue()—— 成功返回Future对象,但其get()方法被调用时,会抛出异常
  • observe()—— 返回Observable对象,当你订阅它的时候,会立即调用 subscriber 的onError方法中止请求
  • toObservable()—— 返回Observable对象,当你订阅它的时候,会立即调用 subscriber 的onError方法中止请求



返回正常回应


若命令成功被执行,Hystrix将回应返回给调用方,或者通过Observable的形式返回。根据上述调用命令方式的不同(如第2条所示),Observable对象会进行一些转换:

image.png


Observable对象的转化


  • execute()—— 产生一个Future对象,行为同.queue()产生的Future对象一样,接着调用其get()方法,生成由内部产生的Observable对象返回的回应
  • queue()—— 将内部产生的Observable对象转换(Decorator模式)成BlockingObservable对象,以产生并返回Future对象
  • observe()—— 产生Observable对象后,立即订阅(ReplaySubject)以使命令得以执行(异步),返回该Observable对象,当你调用其subscribe方法时,重放产生的回应信息和通知给用户提供的订阅者
  • toObservable()—— 返回Observable对象,你必须调用其subscribe方法,以使命令得以执行



熔断器


下图展示了HystrixCommand或HystrixObservableCommand如何与HystrixCircuitBreaker进行交互,以及HystrixCircuitBreaker的决策逻辑流程,包括熔断器内部计数器如何工作。



熔断器执行逻辑


线路的开路闭路详细逻辑如下:

image.png


  • 假设线路内的容量(请求QPS)达到一定阈值(通过


  • HystrixCommandProperties.circuitBreakerRequestVolumeThreshold()配置)


  • 同时,假设线路内的错误率达到一定阈值(通过


  • HystrixCommandProperties.circuitBreakerErrorThresholdPercentage()配置)


  • 熔断器将从『闭路』转换成『开路』


  • 若此时是『开路』状态,熔断器将短路后续所有经过该熔断器的请求,这些请求直接走『失败回退逻辑』


  • **经过一定时间(即『休眠窗口』,通过


  • HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds()配置),后续第一个请求将会被允许通过熔断器(此时熔断器处于『半开』状态)。


  • 若该请求失败,熔断器将又进入『开路』状态,且在休眠窗口内保持此状态;


  • 若该请求成功,熔断器将进入『闭路』状态,回到逻辑1循环往复。









相关文章
|
缓存 Java 应用服务中间件
Hystrix中RequestCache请求缓存技术
Hystrix中RequestCache请求缓存技术
114 0
|
缓存 Java 应用服务中间件
Hystrix线程池技术实现资源隔离
Hystrix线程池技术实现资源隔离
60 0
|
应用服务中间件
高并发下hystrix熔断超时及concurrent.RejectedExecutionException: Rejected command because thread-pool queueSiz...
高并发下hystrix熔断超时及concurrent.RejectedExecutionException: Rejected command because thread-pool queueSiz...
277 0
|
设计模式 缓存 监控
【Hystrix技术指南】(7)故障切换的运作流程原理分析(含源码)
【Hystrix技术指南】(7)故障切换的运作流程原理分析(含源码)
279 0
【Hystrix技术指南】(7)故障切换的运作流程原理分析(含源码)
|
设计模式 缓存 安全
【Hystrix技术指南】(6)请求合并机制原理分析
【Hystrix技术指南】(6)请求合并机制原理分析
197 0
【Hystrix技术指南】(6)请求合并机制原理分析
|
设计模式 缓存 监控
【Hystrix技术指南】(4)故障切换的运作流程
【Hystrix技术指南】(4)故障切换的运作流程
108 0
【Hystrix技术指南】(4)故障切换的运作流程
|
设计模式 Java 数据中心
【Hystrix技术指南】(3)超时机制的原理和实现
【Hystrix技术指南】(3)超时机制的原理和实现
227 0
|
设计模式 缓存 Java
【Hystrix技术指南】(2)参数配置的详细介绍
【Hystrix技术指南】(2)参数配置的详细介绍
178 0
|
设计模式 监控 安全
【Hystrix技术指南】(1)基本使用和配置说明
【Hystrix技术指南】(1)基本使用和配置说明
353 0
|
缓存 监控 Java
高可用架构(10)-Hystrix隔离策略、Command及资源池大小控制(下)
高可用架构(10)-Hystrix隔离策略、Command及资源池大小控制(下)
122 0
高可用架构(10)-Hystrix隔离策略、Command及资源池大小控制(下)