Spring Cloud Netflix微服务组件-Hystrix

目录

Hystrix的主要功能

传统容错手段

超时机制

应用容错三板斧

超时机制

舱壁隔离

熔断降级

侵入式Command用法

改进版一:ribbon与hystrix组合

改进版二:feign与hystrix组合

Hystrix三态转换图

源码分析

流程图

原理流程图

核心实现流程图

入口

HystrixCircuitBerakerConfiguration

如何做功能增强?

@HystrixCommand注解的切面逻辑

CommandExecutor#execute()

HystrixCommand#execute()

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

流程图

熔断器打开时

熔断器关闭时

线程隔离有两种隔离模式

信号量隔离逻辑

线程池隔离逻辑

线程池隔离原理

熔断器源码

流程图

熔断器初始化

熔断器判断机制

如何进入半开状态

滑动时间窗口

原理图

相关配置参数

监控数据收集


Hystrix的主要功能

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

传统容错手段

超时机制

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

af9f3d20e9624a65a69a73bf57990fba.png

全局异常处理器

6268a3a00e164877b6971f89825f5a0a.png控制器中,捕获超时异常,封装成统一的自定义异常并再次抛出,让全局异常处理器来进行处理

ead32e620ec441af8160f4c075aa91e6.png

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

应用容错三板斧

超时机制

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

d07b46c11d16419185f97469cd5a5caf.png

舱壁隔离

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

1d008450df664fd38b8ecc24c3c2e3cc.png

熔断降级

b747210f7ebe40e288f40787051edfdb.png

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

侵入式Command用法

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

d0f200c4915b4cd7b35fa3629f093035.png

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

1c3650ee063c441e8df6c0cb11911d44.png

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

改进版一:ribbon与hystrix组合

a1e2ddbc9f0042a8815baf91f95edba0.png

c553f1776c4248d2a1152aa5da4b383b.png

这里可以配置线程池

改进版二:feign与hystrix组合

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

8b1d6400aae7438e8b4021fa00188559.png

a28c1c082bc448b2a7b44348416796df.png85b1a561201347998fa2ff648db99e46.png

Hystrix的默认配置跳闸阈值

60511a68b2974cd8a97c7fbecdf23b72.png

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

aff49a154fb946e6a1ddfd02ff2a0a82.png

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

Hystrix三态转换图

ba72e4fc930b4ce481d7a20086a8d48d.png

默认失败比例超过50%,则会打开熔断器

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

94ee31ab676d4bb09cf6cdcdf72c7132.png这个就是工作中需要配置的ribbon的超时时间,配置了ribbon的超时时间,那么restTemplate也自动跟随ribbon的超时时间了 

3205ac1ae96c4db28441a4752a390430.png

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

如何关闭hystrix对feign的支持

e5046c45db234927a16c0ea4dec95085.png

5a7a49d96ceb45f89157caf024977855.png

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

生产上需要:

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

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

a81263e29709429b94c0fe57c8a5841e.png

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

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

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

源码分析

流程图

原理流程图

25a08fd56ba94003854bb627590de25f.png

核心实现流程图

727cdd94a9974a69b472e737179a5120.png

入口

a1e2ddbc9f0042a8815baf91f95edba0.png

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

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

5579727128fc44cfb255e01905fd97fb.png

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

aa36fba3588b4251a4107eed4f168bbc.png

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

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

a6be69e2eca344fcaa6ca4cfe0db0436.png

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

a17a3d923a8748d08caf48fe30714d87.png

HystrixCircuitBerakerConfiguration

dc842cda3f6b4bd282315c899228074d.png

如何做功能增强?

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

@HystrixCommand注解的切面逻辑

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

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

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

a501741b16ee4475ab7ed415ca235e1b.png

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

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

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

截止以上的流程图

CommandExecutor#execute()

ed746f165f754663abde6a574e3ba8e7.png

HystrixCommand#execute()

44dd515ea8834875b42e7a8d6b889eca.png

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

e5b66dce859b49cbb95e1ac1d1441e84.png

上述流程对应的流程图

23e414e6eb5e4371a1599d1a28727d53.png

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

1ad7482a56a2483eb75394e422c21921.png

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

231bae12dbaf48d28b4e33c140165e7f.png

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

e255c77d8950426886a7cfb81592e41c.png

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

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

90b6f66a318a40c599acedbe835ec41d.png

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

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

流程图

59fe487e352c42cf84e096c55fbf1c19.png

熔断器打开时

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

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

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

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

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

熔断器关闭时

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

信号量隔离逻辑

20ce1659ed3740fa984cef7fd0707ff4.png

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

线程池隔离逻辑

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

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

executeCommandAndObserve()

8c423d78cbad4f4db36b5b16ec32801f.png

a95e8cb47c144c2dbe5b961e9bc86f00.png 51898b7ff86240e7bd055ee2390f5510.pnggetUserExecutionObservable()方法中就有监听回调方法,回调方法内部,就会通过线程池线程调用GenericCommand的run()

9a2f55bdaeb5400b8b06cba1f4abe077.png

281d0e8871044e6190b85915dd8f7f7f.png

线程池隔离原理

783298f47a0e4bd885138e8787a1093d.png

a17a3d923a8748d08caf48fe30714d87.png

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

562dfa7125f646ff9a28cbf4cb4daae5.png

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

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

AbstractCommand

bd4b1e58197a4554ae38dfdf061fbbe6.png

1b3dce52d5f4438ab58389b6242ead16.png

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

这里就会用到threadPoolKey,

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

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

线程池缓存的技术

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

7cab0163d1eb48208bae5ad7e08b5369.png

a17a3d923a8748d08caf48fe30714d87.png

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

e2b53d88285d425783f08eceae9343c7.png

熔断器源码

hytrix的熔断器是可以直接关掉不启用的

流程图

1045ba63705243618b16100246307868.png

熔断器初始化

每个命令对象,都有自己专属的熔断器,也有自己专属的线程池

如果没有设置启用熔断器,则直接返回NoOpCircuitBreaker

从这里也能看到,

每一个CommandKey方法,都有对应自己唯一的熔断器,互相之间不影响,不会出现一个方法的熔断器打开了,影响到了别的方法的调用执行

熔断器判断机制

每一次请求调用,都会走这个onNext()方法

第179行,判断时间窗口内的所有请求,是否小于滑动窗口能触发熔断的最小请求数,如果小于则代码直接跳过不做任何操作(也就是不做打开熔断器的逻辑)

第185行,说明样本数达标了20个,

  • 第186行,如果错误率小于配置的错误率值,比如小于50%,直接跳过不做任何操作
  • 第192行,如果错误率大于配置的错误率值,比如小于50%,打开熔断器,并给熔断器记录下当前打开时的时间戳circuitOpened(因为熔断器打开后,有个默认5s的持续,超过5s后进入半开状态,放一个请求过去) 

如何进入半开状态

判断当前时间,是否超过熔断器睡觉的5s

如果熔断器睡觉超过5s,则把熔断器置为半开状态

滑动时间窗口

这个滑动时间窗口,也可以用来实现限流策略

原理图

7624b9ac37844b40aedc4670e14da1d0.png

0125ddc9307044f0b3c12912c00e2a3d.png

相关配置参数

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

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

监控数据收集

a430ba81d2e248dfb0cd27fb4e3544e5.png

e6d503accd26406e89da63e9dda2cc77.png

上图画反了,下图是对的

8153d225447a40bb8b2078b6dee113b1.png

对应源码如下:

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

第643行,给execution注册了一个doOnCompleted事件,这个事件就会在当前请求顺利执行成功后,就会回调这个事件对应的回调方法,也就是下面这段逻辑:

15861c844e9f404e8e5a2063844c707d.png

每次请求调用成功没有抛异常,就会调用这个回调方法,这个回调方法内部就会调用断路器HystrixCircuitBreakerImpl的markSuccess()方法,进行调用数据上报数据统计中心

0b6c20fbd56e4c16b97a48de7e80bd4c.png

第207行是上报本次调用数据,比如本次调用是调用成功、熔断器拒绝、线程池拒绝等等不同请求,都需要上报Metrics

如果当前是半开状态,则关闭熔断器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/155553.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 的执行原理(一)

5.1 单表访问之索引合并 我们前边说过 MySQL 在一般情况下执行一个查询时最多只会用到单个二级 索引,但存在有特殊情况,在这些特殊情况下也可能在一个查询中使用到多个二 级索引,MySQL 中这种使用到多个索引来完成一次查询的执行方法称之为&…

基于Android个人理财家庭收支系统uniAPP+vue -hbuiderx-微信小程序vj9n8

摘 要 个人理财APP设计的目的是为用户提供对活动信息和提醒信息管理等方面的平台。 与PC端应用程序相比,个人理财的设计旨在为用户提供一个个人理财信息的管理。用户可以通过APP及时收入信息和支出信息,并对提醒消息进行查看等。 个人理财APP是在Androi…

吴恩达《机器学习》9-4-9-6:实现注意:展开参数、梯度检验、随机初始化

一、实现注意:展开参数 在上一个视频中,讨论了使用反向传播算法计算代价函数的导数。在本视频中,将简要介绍一个实现细节,即如何将参数从矩阵展开为向量。这样做是为了在高级最优化步骤中更方便地使用这些参数。 二、梯度检验 在神经网络中…

【2021集创赛】IEEE杯一等奖:一种28GHz高能效Outphasing PA设计

本作品参与极术社区组织的有奖征集|秀出你的集创赛作品风采,免费电子产品等你拿~活动。 团队介绍 参赛单位:电子科技大学 队伍名称:PA调得队 指导老师:王政 参赛队员:倪梦虎、杨茂旋、张振翼 总决赛奖项:一等奖 1.项…

Golang基础-面向对象篇

文章目录 struct结构体类的表示与封装类的继承多态的基本要素与实现interface空接口反射变量的内置pairreflect包解析Struct TagStruct Tag在json中的应用 struct结构体 在Go语言中,可以使用type 关键字来创建自定义类型,这对于提高代码的可读性和可维护…

掌握这个技巧,你也能成为酒店管理高手!

随着科技的迅猛发展,监控技术在各个领域得到了广泛应用。然而,传统的监控系统在面对水浸等突发事件时,往往无法提供有效的预警和保护。 水浸监控系统通过实时监测水位变化,及时发出警报,以帮助用户采取紧急措施&#x…

EANet:用于医学图像分割的迭代边缘注意力网络

EANet: Iterative edge attention network for medical image segmentation EANet:用于医学图像分割的迭代边缘注意力网络背景贡献实验方法Dynamic scale-aware context module(动态规模感知上下文模块)Edge attention preservation module&a…

深入解析Windows操作系统——概念和工具

文章目录 Windows操作系统的版本Windows NT和Windows 95基础概念和术语内核调试用户模式调试 Windows操作系统的版本 Windows NT和Windows 95 Windows NT和Windows 95之间的一些结构性差异,以及Windows NT优于Windows 95及其后续版本的一些方面: Wind…

慧择解构年轻高客市场长期价值 花旗重申“买入”评级

风险转移、资金配置、社会保障、风险管理,当这四大保险行业基本职能呈现在眼前,人们曾经的第一反应可能是,只有达到一定年龄和社会地位、具备一定经济实力的人群,才会真正严肃对待这些概念。 但是,无论是人均收入水平…

前端环境变量释义import.meta.env.xxx

视频教程 彻底搞懂前端环境变量使用和原理,超清楚_哔哩哔哩_bilibili 添加命令行参数 --modexxxxx 新建.env.xxxx文件,其中.env文件会在所有环境下生效 以VITE_开头,字符串无需加双引号 使用import.meta.env.VITE_xxxxx进行调用

使用pytorch利用神经网络原理进行图片的训练(持续学习中....)

1.做这件事的目的 语言只是工具,使用python训练图片数据,最终会得到.pth的训练文件,java有使用这个文件进行图片识别的工具,顺便整合,我觉得Neo4J正确率太低了,草莓都能识别成为苹果,而且速度慢,不能持续识别视频帧 2.什么是神经网络?(其实就是数学的排列组合最终得到统计结果…

移动云CNP产品介绍

整体介绍 磐舟devops的核心功能是项目管理和CI流程实现。CD能力也是集成的外部开源产品argoCD。所以 磐舟并不以CD能力见长。一般推荐试用磐舟完成CI,然后试用移动云CNP产品完成CD部署工作。 移动云原生技术平台CNP是面向多云多集群场景的应用管理平台。平台以应用…

Linux—简介安装常用命令系统中软件安装项目部署

目录 1. 前言1.1 什么是Linux1.2 为什么要学Linux1.3 学完Linux能干什么 2. Linux简介2.1 主流操作系统2.2 Linux发展历史2.3 Linux系统版本 3. Linux安装3.1 安装方式介绍3.2 安装VMware3.3 安装Linux3.4 网卡设置3.5 安装SSH连接工具3.5.1 SSH连接工具介绍3.5.2 FinalShell安…

大数据可视化是什么?

大数据可视化是将海量数据通过视觉方式呈现出来,以便于人们理解和分析数据的过程。它可以帮人们发现数据之间的关系、趋势和模式,并制定更明智的决策。大数据可视化通常通过图形、图表、地图和仪表盘等视觉元素来呈现数据。这些元素具有直观、易理解的特…

前端uniapp生成海报绘制canvas画布并且保存到相册【实战/带源码/最新】

目录 插件市场效果如下图注意使用my-share.vue插件文件如下图片hch-posterutilsindex.js draw-demo.vuehch-poster.vue 最后 插件市场 插件市场 效果如下图 注意 主要&#xff1a;使用my-share.vue和绘制canvas的hch-poster.vue这两个使用 使用my-share.vue <template&…

时序预测 | MATLAB实现基于LSTM-AdaBoost长短期记忆网络结合AdaBoost时间序列预测

时序预测 | MATLAB实现基于LSTM-AdaBoost长短期记忆网络结合AdaBoost时间序列预测 目录 时序预测 | MATLAB实现基于LSTM-AdaBoost长短期记忆网络结合AdaBoost时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 x 基本介绍 1.Matlab实现LSTM-Adaboost时间序列预测…

SQL基础理论篇(八):视图

文章目录 简介创建视图修改视图删除视图总结参考文献 简介 视图&#xff0c;即VIEW&#xff0c;是SQL中的一个重要概念&#xff0c;它其实是一种虚拟表(非实体数据表&#xff0c;本身不存储数据)。 视图类似于编程中的函数&#xff0c;也可以理解成是一个访问数据的接口。 从…

数据分析思维与模型:群组分析法

群组分析法&#xff0c;也称为群体分析法或集群分析法&#xff0c;是一种研究方法&#xff0c;用于分析和理解群体内的动态、行为模式、意见、决策过程等。这种方法在社会科学、心理学、市场研究、组织行为学等领域有广泛应用。它可以帮助研究人员或组织更好地理解特定群体的特…

C# Onnx DIS高精度图像二类分割

目录 介绍 效果 模型信息 项目 代码 下载 介绍 github地址&#xff1a;https://github.com/xuebinqin/DIS This is the repo for our new project Highly Accurate Dichotomous Image Segmentation 对应的paper是ECCV2022的一篇文章《Highly Accurate Dichotomous Imag…

Windows + Syslog-ng 发送eventlog 到Splunk indexer

1: 背景: 装了window Splunk universal forwarder 的 window server 要把event log 送到linux 的splunk indexer 上,由于网络的原因,不能直接发送数据到splunk indexer的话,要利用跳板机来实现: 2:架构: 3: 先说明每个类型server 上的安装情况: Window server: 安装S…