Spring Cloud Netflix微服务组件-Hystrix

目录

Hystrix的主要功能

传统容错手段

超时机制

应用容错三板斧

超时机制

舱壁隔离

熔断降级

侵入式Command用法

改进版一:ribbon与hystrix组合

改进版二:feign与hystrix组合

Hystrix三态转换图

源码分析

流程图

核心逻辑流程图

核心实现流程图

入口

HystrixCircuitBerakerConfiguration

如何做功能增强?

@HystrixCommand注解的切面逻辑

CommandExecutor#execute()

HystrixCommand#execute()

applyHystrixSemantics()(熔断器核心逻辑)

流程图

熔断器打开时

熔断器关闭时

线程隔离有两种隔离模式

信号量隔离逻辑

线程池隔离逻辑

线程池隔离原理

熔断器源码

滑动时间窗口


Hystrix的主要功能

  • 线程池隔离、
  • 熔断降级、
  • 超时降级、
  • 宕机降级 

传统容错手段

超时机制

是设置RestTemplate的连接超时和读取超时,这是我们在没有使用hytrix这些辅助的分布式工具时的做法

Spring Cloud Netflix微服务组件-Hystrix_第1张图片

全局异常处理器

Spring Cloud Netflix微服务组件-Hystrix_第2张图片控制器中,捕获超时异常,封装成统一的自定义异常并再次抛出,让全局异常处理器来进行处理

Spring Cloud Netflix微服务组件-Hystrix_第3张图片

上面这种,就是传统的容错的处理套路

应用容错三板斧

超时机制

以前没有hytrix的时候,就是直接给RestTemplate设置一个超时时间,RestTemplate调用超时时会抛出TimeoutException,然后我们直接catch到此异常,就直接把同步阻塞的调用线程掐死

Spring Cloud Netflix微服务组件-Hystrix_第4张图片

舱壁隔离

说白了就是资源隔离,比如线程池隔离

1d008450df664fd38b8ecc24c3c2e3cc.png

熔断降级

Spring Cloud Netflix微服务组件-Hystrix_第5张图片

当一段时间内失败次数达到一定阈值,那么熔断器就会打开,此时主业务线程就不会再去调用真正的远程的业务方法,而是直接调用本地早已写好的“降级方法”,返回一个可预知的结果。也就是说:熔断是结果,降级是处理的手段

侵入式Command用法

我们只会下单、支付、调库存等核心高频接口,才需要进行降级,才需要自己在本地写降级方法

Spring Cloud Netflix微服务组件-Hystrix_第6张图片

这样当前端看到返回的订单的订单号为-1时,就可以给客户展示一个友好的页面,比如当前系统开了小差之类的

Spring Cloud Netflix微服务组件-Hystrix_第7张图片

原始的hytrix API处理熔断降级时,就需要这样的强侵入式写法

改进版一:ribbon与hystrix组合

Spring Cloud Netflix微服务组件-Hystrix_第8张图片

Spring Cloud Netflix微服务组件-Hystrix_第9张图片

这里可以配置线程池

改进版二:feign与hystrix组合

feign调用时,通过hystrix进行降级

Spring Cloud Netflix微服务组件-Hystrix_第10张图片

Spring Cloud Netflix微服务组件-Hystrix_第11张图片Spring Cloud Netflix微服务组件-Hystrix_第12张图片

Hystrix的默认配置跳闸阈值

Spring Cloud Netflix微服务组件-Hystrix_第13张图片

上面就是可能会发生降级的三种情况,分别是:宕机降级、超时降级、异常降级

Spring Cloud Netflix微服务组件-Hystrix_第14张图片

生产上上面的配置一般不动,使用默认的配置值

Hystrix三态转换图

Spring Cloud Netflix微服务组件-Hystrix_第15张图片

  • 熔断时间窗口结束后,熔断器状态就从打开转换到半开状态,此时会放过一条请求去请求真正的远程业务方法,如果此次调用成功,则熔断器状态就转成关闭状态,如果此次调用任失败,那么熔断器就又会回到打开状态
  • 什么叫调用失败?客户端去调用服务端接口API,服务端抛了异常并且没有catch直接抛了出来、服务器宕机、服务端接口业务执行耗时太多导致客户端等待接口返回超时
  • 半开状态存在的意义就是为了,让熔断器有机会回到关闭状态(也就是回到能正常去远程调用的状态)

Spring Cloud Netflix微服务组件-Hystrix_第16张图片这个就是工作中需要配置的ribbon的超时时间,配置了ribbon的超时时间,那么restTemplate也自动跟随ribbon的超时时间了 

Spring Cloud Netflix微服务组件-Hystrix_第17张图片

这些参数的设置,就供学习,平时生产大多使用默认参数

如何关闭hystrix对feign的支持

Spring Cloud Netflix微服务组件-Hystrix_第18张图片

Spring Cloud Netflix微服务组件-Hystrix_第19张图片

这里需要hystrix的超时时间需要设置为6000

生产上需要:

hystrix的超时时间  >  (本次调用次数 1 + 出现异常时对当前实例的重试次数 1 + 切换实例后的重试次数 1) * ribbon的超时时间 = 3 * ribbon的超时时间

因为hystrix要保证所有的ribbon调用重试都结束后,hystrix再去插断主线程的调用并给主线程返回降级结果

Spring Cloud Netflix微服务组件-Hystrix_第20张图片

Spring Cloud Netflix微服务组件-Hystrix_第21张图片

第89行,把总体的熔断机制的打开

第92行,可以开始选择某一个方法关闭熔断机制(剩下的,就是局部开启的)

注意上面参数赋值用等号=

源码分析

流程图

核心逻辑流程图

Spring Cloud Netflix微服务组件-Hystrix_第22张图片

核心实现流程图

Spring Cloud Netflix微服务组件-Hystrix_第23张图片

入口

Spring Cloud Netflix微服务组件-Hystrix_第24张图片

通过框架的启动注解开始,实际上这个注解内部就是通过@Import注解,去加载spring.factories中以EnableCircuitBreaker为key的“普通配置类

Spring Cloud Netflix微服务组件-Hystrix_第25张图片

Spring Cloud Netflix微服务组件-Hystrix_第26张图片

这个ImportSelector的作用,就是去找Netflix-core.jar下的spring.factories中以EnableCircuitBreaker为key的键值对,将该key对应的值为一个普通配置类HystrixCircuitBerakerConfiguration,将它注入到ioc容器中来

Spring Cloud Netflix微服务组件-Hystrix_第27张图片

  • 因为Springboot默认的自动配置类读取功能,仅仅只是读取所有jar包下spring.factories中以EnableAutoConfigurationr为key的“自动配置类
  • 各个第三方组件自定义的一些key下所属的“普通配置类”,Springboot是不负责读取的,需要各个第三方组件自己开发针对该key的加载功能
  • 普通配置类以XxxxxConfiguration命名,自动配置类以XxxxxAutoConfiguration命名

Spring Cloud Netflix微服务组件-Hystrix_第28张图片

业务系统首先引入这个starter-netflix-hystrix,这个starter相当于一个聚合器,内部聚合了很多别的功能jar包

这些带有spring-cloud-开头的,就是spring cloud官方为了整合Netflix hystrix组件而开发的自动装配包 

Spring Cloud Netflix微服务组件-Hystrix_第29张图片

优先看与核心功能相关的配置类,比如这里就优先看HystrixCircuitBreakerConfiguration类,像这种HystrixSecurityAutoConfiguration一看就是与安全有关的,非主功能,我们就先不看,这些都是看源码的技巧

Spring Cloud Netflix微服务组件-Hystrix_第30张图片

HystrixCircuitBerakerConfiguration

Spring Cloud Netflix微服务组件-Hystrix_第31张图片

如何做功能增强?

  • 无非就是用代理AOP,横切拦截
  • 或者加待增强对象所拥有的拦截器链中加一个拦截器/过滤器

@HystrixCommand注解的切面逻辑

这一段切面逻辑,也就是每一个被@HystrixCommand注解修饰的方法,在被调起之前,都会先走一遍这个切面增强逻辑。而这一段切面增强逻辑,实际上也就是Hystrix熔断器起作用的逻辑

注意,这都是在客户端执行的代码,也就是请求发起方,此时还没有到接口提供方(服务端)

Spring Cloud Netflix微服务组件-Hystrix_第32张图片

第90行,同时会拦截@HystrixCommand,还有合并请求的@HystrixCollapser

Spring Cloud Netflix微服务组件-Hystrix_第33张图片

第96行,会创建一个HystrixInvokable,如下是第96行的create()逻辑:

Spring Cloud Netflix微服务组件-Hystrix_第34张图片

GenericCommand命令模式对象中有两个核心方法,一个就是run()也就是正常的业务逻辑方法,另一个就是getFallback()也就是降级方法,getFallback()内部会通过反射调用@HystrixCommand中配置的fallBackMethod方法

从这里也知道,返回的HystrixInvokable,实际上就是一个GenericCommand

Spring Cloud Netflix微服务组件-Hystrix_第35张图片

截止以上的流程图

CommandExecutor#execute()

Spring Cloud Netflix微服务组件-Hystrix_第36张图片

Spring Cloud Netflix微服务组件-Hystrix_第37张图片

HystrixCommand#execute()

Spring Cloud Netflix微服务组件-Hystrix_第38张图片

queue()返回一个Future凭证,从这里开始就是一堆的响应式变成了,各种定义监听与事件响应执行来串起整个执行流程

Spring Cloud Netflix微服务组件-Hystrix_第39张图片

上述流程对应的流程图

Spring Cloud Netflix微服务组件-Hystrix_第40张图片

响应式编程的定义语法(rxJava响应式编程框架,手机上用的比较多)响应式编程说白了就是一堆的观察者模式,zookeeper里面的节点内容变化也会触发监听器执行,这都是观察者模式

Spring Cloud Netflix微服务组件-Hystrix_第41张图片

总体原理就是:Observable是被观察者,Observer是观察者,当被观察者发生变化时就会回调观察者

Spring Cloud Netflix微服务组件-Hystrix_第42张图片

这里就把34行就当做定义了一个观察者,45行就定义了一个被观察者

Spring Cloud Netflix微服务组件-Hystrix_第43张图片

Spring Cloud Netflix微服务组件-Hystrix_第44张图片

这里把观察者,注册绑定到被观察者上,以后被观察者发生不同事件,就会回调不同的观察者的call()方法

这里就是被@HystrixCommand注解修饰的方法,在发起一次调用时,如果调用的方法正常返回

Spring Cloud Netflix微服务组件-Hystrix_第45张图片

这里就出现了一个核心观察者applyHystrixSemantics()

applyHystrixSemantics()(熔断器核心逻辑)

流程图

Spring Cloud Netflix微服务组件-Hystrix_第46张图片

Spring Cloud Netflix微服务组件-Hystrix_第47张图片

熔断器打开时

Spring Cloud Netflix微服务组件-Hystrix_第48张图片

当发现当前熔断器是打开状态,则调用FallBack方法,也就是调用GenericCommand的getFallBack()方法,getFallBack()方法会去找到@HystrixCommand中配置的fallBackMethod方法,并执行这个fallBackMethod方法方法(最终,就是通过方法名,通过反射来调用到fallBackMethod方法的)

Spring Cloud Netflix微服务组件-Hystrix_第49张图片

第523行,判断当前熔断器状态,是否为打开状态

Spring Cloud Netflix微服务组件-Hystrix_第50张图片

第523行,判断当前熔断器状态是关闭状态,则走524行开始的逻辑,如果判断熔断器当前是打开状态,则走557行的FallBack逻辑,也就是调用降级逻辑

Spring Cloud Netflix微服务组件-Hystrix_第51张图片

判断当前熔断器状态,是否为打开状态

熔断器可以强制配置为关闭,但是这里代码写的有点难理解,与正常思维判断逻辑是个反的

熔断器关闭时

Spring Cloud Netflix微服务组件-Hystrix_第52张图片

线程隔离有两种隔离模式
  • 一种是信号量的隔离模式,信号量计数器满了以后也会走降级逻辑
  • 一种是线程池的隔离模式,线程池满了以后也会走降级逻辑

信号量隔离逻辑

Spring Cloud Netflix微服务组件-Hystrix_第53张图片

Spring Cloud Netflix微服务组件-Hystrix_第54张图片

信号量的隔离模式下,如果542行获取信号量失败,则执行554行的信号量拒绝FallBack,但是现实中基本都用线程池隔离模式

线程池隔离逻辑

这是在没有配置信号量策略时

Spring Cloud Netflix微服务组件-Hystrix_第55张图片

Spring Cloud Netflix微服务组件-Hystrix_第56张图片

如果没有配置信号量,那么下面的第542行会一直返回true,从而进入真正的线程池隔离的逻辑

Spring Cloud Netflix微服务组件-Hystrix_第57张图片

executeCommandAndObserve()

Spring Cloud Netflix微服务组件-Hystrix_第58张图片

Spring Cloud Netflix微服务组件-Hystrix_第59张图片 Spring Cloud Netflix微服务组件-Hystrix_第60张图片getUserExecutionObservable()方法中就有监听回调方法,回调方法内部,就会通过线程池线程调用GenericCommand的run()

Spring Cloud Netflix微服务组件-Hystrix_第61张图片

Spring Cloud Netflix微服务组件-Hystrix_第62张图片

线程池隔离原理

Spring Cloud Netflix微服务组件-Hystrix_第63张图片

Spring Cloud Netflix微服务组件-Hystrix_第64张图片

大体流程:用户在调用findById()方法时,hystrix写的AOP切面类会拦截这个注解,拦截这个注解后会初始化一个GenericCommand命令,在初始化这个GenericCommand命令内部,就会通过这些线程池的配置,来初始化该命令特有的执行线程池

Spring Cloud Netflix微服务组件-Hystrix_第65张图片

上上图@HystrixCommand注解中的所有信息,默认就会被保存在这个元信息MetaHolder中去,Spring的代码都是很统一的,这种注解的元数据一般都是用MetaXxxxx来保存的 

这里就通过注解的元信息来构造了一个GenericCommand命令。GenericCommand是AbstractCommand的子类

AbstractCommand

Spring Cloud Netflix微服务组件-Hystrix_第66张图片

Spring Cloud Netflix微服务组件-Hystrix_第67张图片

@HystrixCommand注解中的所有信息,默认就会被保存在这个元信息MetaHolder中,从这些元信息中,就能获得到threadPoolProperties信息

这里就会用到threadPoolKey,

Spring Cloud Netflix微服务组件-Hystrix_第68张图片

所以,这里就实现了有多少key就会初始化出来多少个线程池,也就实现了通过key的不同来实现不同粒度的隔离 

如果有多个业务方法配置了相同的key,那么也就实现了多个hystrix方法公用了同一个线程池

Spring Cloud Netflix微服务组件-Hystrix_第69张图片

线程池缓存的技术

以后线程池隔离执行时,就是把当前的GenericCommand#run()方法,丢进这个threadPool中去执行的

Spring Cloud Netflix微服务组件-Hystrix_第70张图片

Spring Cloud Netflix微服务组件-Hystrix_第71张图片

利用线程池缓存的技术,实现多个用户方法公用同一个线程池的目的,只需要多个方法,配置相同的commandKey和threadPoolKey

Spring Cloud Netflix微服务组件-Hystrix_第72张图片

熔断器源码

Spring Cloud Netflix微服务组件-Hystrix_第73张图片

滑动时间窗口

Spring Cloud Netflix微服务组件-Hystrix_第74张图片

Spring Cloud Netflix微服务组件-Hystrix_第75张图片

Spring Cloud Netflix微服务组件-Hystrix_第76张图片

numbuckets就是为了调整时间的统计粒度,统计粒度越细则熔断器对于网络堵塞等异常状态的感应就更加灵敏

滑动窗口触发熔断的最小请求数,这个是整个时间窗口内的,这是一种兜底策略

Spring Cloud Netflix微服务组件-Hystrix_第77张图片

Spring Cloud Netflix微服务组件-Hystrix_第78张图片

Spring Cloud Netflix微服务组件-Hystrix_第79张图片

上图画反了,下图是对的

Spring Cloud Netflix微服务组件-Hystrix_第80张图片

对应源码如下:

Spring Cloud Netflix微服务组件-Hystrix_第81张图片

每次请求,都会走上面的判断逻辑

Spring Cloud Netflix微服务组件-Hystrix_第82张图片

每次请求调用成功没有抛异常,就会调用这个回调方法,这个回调方法内部就会调用断路器进行调用数据上报

Spring Cloud Netflix微服务组件-Hystrix_第83张图片

206行是上报本次调用数据

你可能感兴趣的:(微服务,微服务,hystrix)