SpringCloud(三)之我学 Hystrix

1、断路器

  在消费服务的启动类,添加注解:@EnableCircuitBreaker,在消费服务的调用类上,添加注解:@HystrixCommand(fallbackMethod = "") -> 失败了调的方法。(熔断超时默认 2s )

  当被调用的服务,超时或者未反应/down掉,就会触发熔断请求,返回定义的逻辑。

  工作流程:

  1)、加注解:@HystrixCommand 或 @HystrixObservableCommand ,前者用于依赖的服务返回单个操作结果的时候,后者用于依赖的服务返回多个操作结果的时候。(具体的实现看书籍)

  命令模式,将客户端请求封装为一个对象,能让不同的请求对客户端进行参数化。(让不同类型的参数,都可以请求)

  2)、命令执行:

  HystrixCommand 实现了 execute()、queue() 执行方法。

  execute():同步执行,从依赖的服务返回一个单一的结果对象,或错误时抛出异常,R value = command.execute();

  queue():异步执行,直接返回一个 Future 对象,其中包含了服务执行结束时返回的单一结果对象,Future<R> fValue = command.queue();

  HystrixObservableCommand 实现了 observe()、toObservable() 执行方法。

  Observable<R> obValue = command.observe(),代表操作了多个结果,返回 HotObservanle;

  Observable<R> ocValue = command.toObservable(),也代表操作了多个结果,返回 Cold Observable;

  Hystrix 底层实现了大量的 RxJava,RxJava 的观察者-订阅者模式。

  Observable 向订阅者 Subscriber 对象发布事件(即异服务调用),一个Observable 可以发出多个事件,直到结束或者发生异常。每发出一个事件,就会调用对应观察者 Subscriber.onNext() 方法。最后一定会调用 Subscriber.onCompleted() 或者 Subscriber.onError() 结束该时间的操作流。

  3)、结果是否被缓存:当命令的请求缓存功能开启,命令缓存命中,缓存的结果就会以 Observable 对象的形式返回。

  4)、断路器是否打开: - 断路器是否已经开始运行

  命令结果没有命中缓存中,如果断路器打开,Hystrix 不会执行命令,而是转到 fallback 处理逻辑。如果断路器关闭,则继续执行。

  5)、线程池/请求队列/信号量是否占满: - 线程太多

  如果与命令相关的线程池或请求队列或者信号量已经占满,则 Hystrix 也不会执行命令,而是转接到 fallback 处理逻辑。

  该线程池并非容易的线程池,而是每个依赖服务的专有线程池。

  6)、请求依赖服务:

  HystrixObserveableCommand.construct() 或 HystrixCommand.run(),决定了采取什么样的方式去请求依赖服务。

  第一种返回一个 Observable 对象来发射多个结果,或通过 onError 发送错误通知;

  第二种返回一个单一的结果,或者抛出异常。

  超时也会转到 fallback 处理逻辑。

  7)、计算断路器的健康度: - 服务调用失败/超时等超过设置

  Hystrix 会将成功、失败、拒绝、超时等信息报告给断路器,断路器会维护一组计数器来统计这些数据。根据数据值,来对某个依赖服务的请求进行 "熔断/短路",直到恢复期结束。在恢复期结束后,再根据统计数据判断是否还是未达到健康指标,或再次"熔断/短路"。

  8)、fallback 处理:- 回退 - 服务降级

  当命令执行失败的时候,Hystrix 会进入 fallback 尝试回退处理,该操作叫做 "服务降级"。

  第4、5、6步都可能会引起服务降级。

  最终的降级逻辑一定不是一个依赖网络请求的处理,而是一个能够稳定返回结果的处理逻辑。

  HystrixCommand.getFallback() 来实现服务降级;

  HystrixObservableCommand.resumeWithFallback() 来实现降级逻辑。

  9)、返回成功的响应:

2、断路器原理

  HystrixCricuitBreaker 接口:

  allowRequest:每个 hystrix 命令的请求都通过它判断是否被执行;

  isOpen:返回当前断路器是否打开;

  markSuccess():用来闭合断路器,并重置度量指标对象。

  HystrixCricuitBreakImpl 是实现类,有几个重要核心对象,一个是 HystrixCommand 实例的属性对象,一个是记录各个度量指标的对象,一个是断路器是否打开的标志,一个是断路器打开或上一次测试的时间戳。

  断路器从关闭到打开(默认时间窗10s的请求信息快照):

  1)、请求总数 QPS 在预设的阈值范围内就返回 false,表示断路器还是关闭。阈值默认值20。

  2)、错误百分比在阈值范围内就返回 false,表示断路器还是关闭。默认是50。

  3)、以上两个条件都不满足,断路器就设置为打开状态(熔断/短路)。如果是从关闭状态切到打开状态,就将当前时间记录到上面的时间戳对象中。

  allowSingleTest() 为断路器再设置一个休眠时间(默认5s),在该休眠时间达到只有,再次允许请求尝试访问。若请求再次失败,断路器又进入打开状态。请求成功,则是关闭状态。

  所以 allowSingleTest() 与 isOpen() 方法的配合,实现了断路器的打开和关闭状态的切换。

3、依赖隔离

  会为每个依赖服务创建一个独立的线程池,这样就算某个依赖服务出现问题后,也只对该依赖服务的调用产生影响,不影响其他依赖服务。

  特点:

  依赖的服务从失效恢复正常后,它的线程池会被清理并且能够马上恢复健康服务。容器级别的清理 恢复速度慢的多;

  当依赖的服务出现配置错误的时候,线程池会被快速反映出此问题(失败、延迟、超时、拒绝等增加情况)。

  线程池的开销在设计的时候做过实验,消耗相对于来说是微乎其微的。对于某些需求来说,如果该消耗觉得很大,又用了信号量来优化。

  信号量控制单个依赖服务的并发量,但是不能设置超时和实现异步访问。线程池和信号量可以切换。

  在降级逻辑,Hystrix 尝试降级逻辑时,会在调用线程中使用信号量。或者命令执行。

4、使用详解

  1)、创建请求命令

  可以用继承 HystrixCommand 或者 @HystrixCommand 来实现熔断,注解添加在异服务之间调用的接口上。

  并且该注解可以实现 同步/异步 的操作。异步用 Future<T> 接收返回参数。

  2)、定义服务降级

  fallback 是 Hystrix 命令执行失败后使用的后备办法,实现服务的降级处理逻辑。

  继承方式的话,用重载 getFallback() 方法来实现降级处理;

  注解方式 @HystrixCommand(fallbackMethod = "failMethod") ,定义一个 faliMethod 方法,作为降级处理。(在同一个类中)

  3)、异常处理

  当服务调用发生异常,除了 HystrixBadRequestException 之外,其他异常都会被 Hystrix 认为命令执行失败,并触发服务降级的处理逻辑。

  使用注解 @HystrixCommand(ignoreExceptions = {XXException.class}) 可以忽略指定异常类型。当遇到该类型的异常时,就会被包装 HystrixBadRequestException 异常抛出,而不会触发降级的处理逻辑。

  4)、异常获取

  异常获取到后,可以根据不同的异常判断,做出不同的处理方式。直接在 fallback() 方法里定义一个 Throwable e ,就可以获取触发降级的具体异常内容。(e.getMessage())

  5)、命令名称、分组以及线程池划分

  Hystrix 会让相同组名的命令使用同一个线程池。所以创建 Hystrix 命令时,为其制定命令组名来实现默认的线程池划分。(还提供了 HystrixThreadPoolKey 来对线程池进行设置,进行更加细粒度的线程池划分,实际情况通常使用这一种划分方式)

  注解方式实现:@HystrixCommand(commandKey="getUserById",groupKey="UserGroup",ThreadPoolKey="getUserByIdThread")

  6)、请求缓存

  开启请求缓存功能:继承方式,重载 getCacheKey() 方式来开启请求缓存。

  好处:

  减少重复请求数,降低依赖服务的并发度(降低压力);

  在同一用户请求的上下文中,相同依赖服务的返回数据一致;

  请求缓存在 run() 和 construct() 执行之前生效,可以减少不必要的线程开销;

  清理失效缓存功能:通过 HystrixRequestCache.clear() 方法来进行缓存的清理,在做更新操作时,就将缓存清理掉。

  注解方式:@CacheResult 标记请求命令返回的结果应该被缓存,必须和 @HystrixCommand 结合使用;

  @CacheRemove 让请求命令的缓存失效,失效的缓存是根据 key 来的。(commandKey)

  @CacheKey 给参数添加标记,使之成为缓存的 key。

  7)、请求合并

  远程调用最常见的问题就是 通信消耗和连接总数。Hystrix 提供了 HystrixCollapser 来实现请求的合并,以减少通信消耗和线程池的占用。

  HystrixCollapser 实现了 在 @HystrixCommand 之前放置了一个合并处理器,将处于一个很短时间内(默认10ms)对同一依赖服务的多个请求进行整合并以批量方式发起请求。

posted @ 2019-07-19 16:12  几近虚年  阅读(221)  评论(0编辑  收藏  举报