SpringCloud Hystrix进阶应用(三)

SpringCloud Hystrix源码解析(三)

看这篇之前请看

SpringCloud Hystrix源码解析(一)

SpringCloud Hystrix源码解析(二)

异步与异步回调执行命令

Hystrix 除了同步执行命令,还可以异步以及异步回调执行命令。异步执行命令需要定义函数的返回方式为Future ,如下面的例子所示:

@HystrixCommand(fallbackMethod =”instanceinfoGetFailAsync ” )
public Future<Instance> getinstanceByServ 工ceidAsync(String serviceid) {
     
logger.info (” Can not get Instance by serviceid {
     }, serviceid) ;
return new AsyncResult <Instance> () {
     
@Override
public Instance invoke() {
     
return restTemplate . getForEntity ( ” http : //FEIGN SERVICE/fe ign serv工ce/
instance/{
     serviceid}, Instance . class , serviceid) . getBody() ;
}
};
}

在这种情况下,命令的失败回滚方法也需要通过@HystrixCommand 进行注解,如下所示:

@HystrixCommand
public Future<Instance >Instance InfoGetFailAsync(String serviceid){
     
logger 工nfo( " Can not get Instance by serviceid {
     }, serviceid) ;
return new AsyncResult <工nsta口Ce> () {
     
@Override
public Instance Invoke() {
     
return new Instance ( ” error ",” error ”, 。) ;
}
};
}

同样, 想要异步回调执行命令, 只需要将包装函数的返回值设定为Observable 即可,如下所示:
SpringCloud Hystrix进阶应用(三)_第1张图片
异步回调执行命令并不需要Fallback 方法被@HystrixCommand 注解。可以通过设置observableExecutionMode 来决定返回的Observable 是否已经开始执行命令: EAGER 将会返回通过AbstractCommand#observable 方法生成的Observable 此时的命令已经开始执行了;而LAZY 则会返回通过AbstractCommand#toObservable 方法生成的Observable , 返回的
Observale 必须订阅后才会真正开始执行命令。上面的例子中设定的observableExecutionMode为ObservableExecutionMode.LAZY 。

继承HystrixCommand

除了通过注解的方式声明Hystrix 包装函数,还可以通过继承Hystrix Command 以及HystrixObservableCommand 抽象类接口来包装需要保护的远程调用函数。

继承HystrixCommand

下面将通过继承HystrixCommand 抽象类来实现特定的HystrixCommand 子类,代码如下所示:

SpringCloud Hystrix进阶应用(三)_第2张图片
run 方法中是需要进行包装的远程调用函数, 是必须要实现的抽象方法, getFallback方法是该命令执行失败后的失败回滚方法,属于可选实现。值得注意的是,在构造HystrixCommand 时-至少要为它指定一个HystrixCommandGroupKey ,在通过注解的方式生
成HystrixCommand 时,该值一般是注解方法所在类的运行时类名。
在使用C ustomH ystrixCommand 时,会发现无法在#run 方法中传递参数,所以需要在构造器中携带# run 方法的相关参数,如上述例子中的构造函数,传递被保护方法执行所需要的参数:

protected CustomHystrixCommand(RestTemplate restTemplate, String serviceid) {
      . . . }

调用命令的方式很简单,如下所示:

CustomH.ystrixCommand customHystrixCommand = new CustomHystrixCommand(restTemplate ,serviceid);
Instance instance = customHystrixCommand . execute();

创建一个CustomHystrixCommand , 并调用它的execute 方法, 即可按照Hystrix 的逻辑执行命令。如果想要以异步方式执行命令,可以调用它的queue 方法,如下所示:

CustomHystrixCommand customH.ystrixCommand = new CustomHystrixCommand(restTemplate,
serviceid) ;
Future<Instance> future= customHystrixCommand . queue() ;

还需要注意的是,一个C ustomHystrixComman d 只能执行一次( execute 方法或者queue方法),所以每次使用都要创建一个新的Command 。为了满足自定义HystrixCommand 配置的需求, HystrixCommand 抽象类中定义了多种构造器,用于对构建的Command 配置进行设置。

继承HystrixObservableCommand
除了HystrixCommand ,还可以继承HystrixObservableCommand 来构建以异步回调执行命令的Command

请求合并

Hystrix 还提供了请求合并的功能。多个请求被合并为一个请求进行一次性处理,可以有效减少网络通信和线程池资源。请求合并之后一个请求原本可能在6 毫秒之内能够结束, 现在必须等待请求合并周期后( I 0 毫秒)才能发送请求,增加了请求的时间( 16 毫秒) 。但是请求合并在处理高并发和高延迟命令上效果极佳。

它提供两种方式进行请求合并: request-scoped 收集一个Hystrix RequestContext 中的请求集合成一个批次;而globally-scoped 将多个HystrixRequestContext 中的请求集合成一个批次,这需要应用的下游依赖能够支持在一个命令调用中处理多个HystrixRequestContext 。
HystrixReuestContext 中包含和管理着HystrixRquestVariableDefault , HystrixRequestγariableDefault中提供了请求范围内的相关变量,所以在同一请求中的多个线程可以分享状态,HystrixRequestContext 也可以通过Hystri xRequestVari ableDefault 收集到请求范围内相同的HystrixCommand 进行合并。

通过注解方式进行请求合并
单个请求需要使用@HystrixCollapser 注解修饰,并指batchMethod 方法,这里我们设置请求合并的周期为100 秒。由于请求合并中不能同步等待结果,所以单个请求返回的结果为Future ,即需要异步等待结果。

batchMethod 方法需要被@Hystri x Command 注解,说明这是一个被HystrixCommand封装的方法

请求开始前需要为请求初始化HystrixRequestContext ,用于在同一请求中的线程间共享数据,封装批量请求,请求结束前需要关闭HystrixRequestContext

结果显示只执行了两次批量操作,前三个为一次,最后一个单独进行。如果在请求合并周期内直接调用Future#get 方法阻塞等待同步结果,将会强行合并请求,增加远程请求次数

主线程将会因为同步等待而阻塞后面命令没有提交合并,请求合并只进行到test2中,所以上面代码中将会执行三次批量请求,前两个为一次,第三个和第四个分别为
一次。

继承HystrixCollapser
请求合并命令同样也可以通过自定义的方式实现, 只需继承HystrixCollapser 抽象类
在构造函数中需要指定CollapserKey,用来标记被合并请求的键值。CustomCollapseCommand样可以通过Setter 的方式修改默认配置。

同时还需要实现三个方法, getRequestArgument 方法获取被合并的单个请求的参数,createCommand 方法用来生成进行批量请求的命令Command, mapResponseToRequests 方法是将批量请求的结果与合并的请求进行匹配以返回对应的请求结果。

需要注意的是,因为HystrixCollapser 继承了Hystrixlnvokable ,它同样提供execute 同步获取结果,但是调用execute 获取结果时,会因为同步等待的原因阻塞主线程,导致后面的请求无法提交合并,增加远程调用的次数。

总结

微服务架构下,每个微服务独立部署运行,业务之间的搞合使微服务间不可避免地会发生相互调用。由于网络故障或者程序故障,服务提供者很容易无法响应服务调用者的请求,引起服务雪崩,最坏情况下可能导致整个分布式系统的瘫痪。Hystrix 为S pri ng C l ou d 中微服务间的相互调用提供了强大的容错保护。它通过将服务调用者和服务提供者隔离的方式,在服务提供者失效的情况下,保护服务调用者的线程资源,保证系统的整体稳定性,防止服务雪崩效应的发生。Hys trix 提供了很多服务容锚的机制和手段,如断路器、资源隔离、失败回滚等,同时也提供接近实时的执行监控,为服务的健康运行保驾护航。

你可能感兴趣的:(spring,java)