服务容错保护断路器Hystrix之七:做到自动降级

从《高可用服务设计之二:Rate limiting 限流与降级》中的“自动降级”中,我们这边将系统遇到“危险”时采取的整套应急方案和措施统一称为降级或服务降级。想要帮助服务做到自动降级,需要先做到如下几个步骤:

  1. 可配置的降级策略:降级策略=达到降级的条件+降级后的处理方案,策略一定得可配置,因为不同的服务对服务的质量定义不一样,降级的方案也将不一样。
  2. 可识别的降级边界:一定要精确的知道需要对谁进行降级,可以是一个对外服务、对下游的一个依赖或者是内部一段处理逻辑。降级边界主要用来植入降级逻辑。
  3. 数据采集:是否达到降级条件依赖于采集的数据,这些数据可以是当前某段时间的数据,也可以是很长一段时间的历史数据。
  4. 行为干预:进入降级状态后将会对正常的业务流程产生干预,可能是限流、熔断,也可能是同步流程变为异步流程等(比如发送MQ的变成oneway的形式)等。
  5. 结果干预:是返回null,还是默认值,还是流程上的同步改异步等。
  6. 快速恢复:即如何从降级状态变回正常状态,这也需要达到某些条件。

我们来逐步看下Hystrix是如何做到以上几点的,

### 可配置的降级策略 ###

Hystrix提供了三种降级策略:并发、耗时和错误率,而Hystrix的设计本身就能很好的支持动态的调整这些策略(简单的说就是调整并发、耗时和错误率的阈值),当然,如何去动态调整需要用户自己来实现,Hystrix只提供了入口,就是说,Hystrix并没有提供一个服务端界面来动态调整这些策略,这多少有点让人遗憾。如果要了解Hystrix具体的策略配置,可以看看HystrixCommandProperties 和 HystrixThreadPoolProperties两个类。

### 可识别的降级边界 ###

降级工具面临的第一个难题就是如何在业务代码中植入降级逻辑,业务研发人员得提前明确和定义哪些地方是风险点,然后将这些地方的逻辑抽取出来,Hystrix包装需降级的业务逻辑采用的是Command设计模式,我们知道,命令模式主要是将请求封装到对象内部,让我们使用对象一样来使用请求。这样对Hystrix大有好处,因为你需要降级的业务逻辑和数据已经封装成一个Command对象交给Hystrix了,Hystrix直接来接管业务逻辑的执行权,该何时调用,或者甚至不调用都可以,我们来看看Hystrix定义的命令接口。

只需要简单继承HystrixCommand,就相当于接入了Hystrix,泛型R代表返回值类型,在run()方法中直接实现正常的业务逻辑,并返回R类型的结果,如果降级后需要返回特殊的值,你只需要覆盖getFallback()方法即可

举个例子,见《服务容错保护断路器Hystrix之六:缓存功能的使用

可以看出,我们创建了一个BookCommand 的实例,然后调用了execute方法来获取结果,这样就基本完成了,Hystrix库类已经给逻辑附上了缓存、自动降级等逻辑了,当然里面使用了大量Hystrix默认的降级策略配置(本文不是Hystrix使用的详细教程,所以这里主要突出的是用法而不强调具体的策略配置)。这里同样也说明了为什么动态调整配置是很容易的,因为每个请求都会新建Command对象(注意,Command对象是有状态的,不能重用),你只需要在创建时调整策略参数就行了,当然,这得用户自己来实现。

虽然看起来很简单,但老司机马上会发现问题:

  1. 系统中每一处需要降级的逻辑都需要将其封装成一个Command类,哪怕需要降级的方法只有一行代码。如果一个系统有一百个需要降级的点,那么我们需要在系统中新增一百个Command类,有时候这让人难以接受。
  2. 对老的业务系统来说,接入Hystrix将意味着巨大的工作量,因为你要把很多逻辑都封装成Command,你能接受但测试同学未必愿意。
  3. 每次请求都将创建一个Command对象,因为Command对象包含了降级逻辑的大部分操作,是个重状态的对象,不能复用,如果QPS过高,将产生大量的朝生夕死的对象,对内存分配和GC将产生一定的压力。

很多用户确实也提出过抱怨,为何Hystrix的侵入性那么强?但Hystrix设计者们这么做自然有他们的道理(详见:https://github.com/Netflix/Hystrix/wiki/FAQ%20:%20General 的Why is it so intrusive?部分),他们认为,我们需要给应用的依赖提供一个清晰的屏障,使用Command模式不仅仅是出于功能上的原因,也是作为一种标准机制,通过Command对象来向用户传递它是受保护的资源。可见,Hystrix的设计者们并不建议我们使用基于注解或AOP来作为接入Hystrix的方式,但他们仍然说:If you still feelstrongly that you shouldn't have to modify libraries and add command objectsthen perhaps you can contribute an AOP module.(直译过来就是如果你嫌麻烦不想创建这么多Command对象,有本事你自己去实现AOP啊!开个玩笑(*^__^*) )。 

### 数据采集 ###

收集数据是必不可少的一步,每个降级点(需要采取降级保护的点)的数据是独立的,所以我们可以给每个降级点配置单独的策略。这些策略一般是建立在我们对这些降级点的了解之上的,初期甚至可以先观察一下采集的数据来指定降级策略。采集哪些数据?数据如何存储?数据如何上报?这都是Hystrix需要考虑的问题,Hystrix采用的是滑动窗口+分桶的形式来采集数据(具体细节见另一篇),这样既解决了数据在统计周期间切换而带来的跳变问题(通过时间窗口),也控制了切换了力度(通过桶大小)。另一个有意思的地方是,与常规的同步统计数据的方式不同,Hystrix采用的是RxJava来进行事件流的异步统计数据,类似于观察者模式(具体细节见另一篇),这样做的好处是降低统计时阻塞业务逻辑的风险,在某些情况下还能享受多核CPU所带来的性能上的收益。 

### 行为干预 ###

一旦发现采集的数据命中了降级策略,那么降级工具就将对请求进行行为干预,行为干预是评价一个降级工具好坏的重要指标,它的设计直接关系到系统的“弹性”到底有多大。但有时候行为干预和上面提到的数据采集这两个动作是同时完成的,比如使用信号量、线程池或者令牌桶算法来进行降级的时候。行为干预的设计是很有技巧的,一般来说有如下两种方案:

  1. 实时采集(当前某段时间周期的)数据,对每笔请求都进行策略判断(每笔请求都会加入数据并进行分析),一旦命中策略,当即对这笔请求进行行为干预,如果没有命中,则执行正常的业务逻辑。
  2. 实时采集(当前某段时间周期的)数据,对每笔请求都进行策略判断(每笔请求都会加入数据并进行分析),一旦有一笔请求命中了策略,接下来的一段时间(可配)内的所有请求都会被行为干预,哪怕接下来再也没有请求命中策略,一直到该段时间过去。

方案a似乎是比较合理的,它总是将系统的行为尽可能的控制在我们预期之内(即各项指标都在配置的策略之下),但多数情况下,我们配置策略会比较宽泛,不那么严格,那这时候采用方案a对系统来说还是有一定的风险。这时候就出现了相对更激进的方案b!一但某些请求导致统计数据触犯了降级策略,那么系统会对后续一段时间的所有请求进行降级处理,即我们熟知的降级延长。而Hystrix将两者结合起来了,让行为干预更加灵活。

### 结果干预 ###

被降级后的请求是应该返回null?还是默认值?还是抛异常?这些都要根据业务而定。Hystrix也在HystrixCommand提供了getFallback方法来方便用户返回降级后的结果。

### 快速恢复 ###

快速恢复功能在那些经常由于外部因素而导致进入降级状态的系统来说尤为重要,降级系统或工具的一个重大目标就是自动性,摆脱需要人为控制开关来保证功能熔断的“原始时代”,所以当外部条件已经恢复,系统也应该在最短的时间内恢复到正常服务状态,这就要求降级系统能够在让业务系统进入降级状态的同时,让业务系统有探测外界环境的机会。大多数降级系统都会在一段时间后“放”一笔请求进来,让它去“试一试”,如果结果是成功的,那么将让业务系统恢复到正常状态,Hystrix同样也是采用这种做法。

如果看到这里,其实大家已经对Hystrix的功能有一定的了解,这里再给一张官方的图:

这张图已经充分说明了官方推荐的是通过Command+线程池的模式来进行业务功能的剥离和管理,这些大大小小的线程池,使用不当,将产生隐患,所以千万不要让Hystrix的这种用法变成反模式。

 

在最后,我们来简单总结下Hystrix的特色:

  1. Hystrix内部大量使用了响应式编程模型,通过RxJava库,把能异步做的都做成异步了。这似乎能降低代码复杂度(我是指对RxJava了解的人),并且在多核CPU的服务器上能带来意外性能收获
  2. Hystrix能做到通过并发、耗时和异常来进行降级,并能在(并发、限流或内部产生的异常导致的)错误率达到一定阈值时进行服务熔断,并且还能做到从降级状态快速恢复。
  3. Hystrix通过Command模式来包装降级业务,这有时候提高了接入成本。
  4. Hystrix只提供了策略变更的入口,但具体的策略可视化和动态配置还是得用户来实现,这确实非常尴尬。
  5. Hystrix默认的仪表盘只提供了简单的实时数据显示,如果要持久化历史数据,也得用户来实现。

 

转载于:https://www.cnblogs.com/duanxz/p/9679596.html

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

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

相关文章

from表单提交和JSON区别

form表单是“键值对”的数据格式,例如: a1&b2&c3 而json格式则与之不同,如下: {"a":1,"b":2,"c":3} 传递的数据比较简单,那么两种方式基本上没什么大区别(当然后台接…

在一个数组中,如何确定所需元素在数组中的位置.

package wac.wev.LianXi; public class CiShu {public static void main(String[] args){//创建一个数组int[] arr {101,23,123,34,13};int y Yuan(arr,13);System.out.println(y);}//1)明确返回值:int//2)明确形式参数:int[] arr 和 int value(value表示所需元素)public stati…

Java实现Excel导入数据库,数据库中的数据导入到Excel

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 实现的功能: Java实现Excel导入数据库,如果存在就更新数据库中的数据导入到Excel1、添加jxl.jar mysql-connect…

FreeBSD 10 将使用 Clang 编译器替换 GCC

来自 phoronix 的消息称,根据 FreeBSD 2012 第一季度的状态报告 显示,来自 LLVM 的 Clang 编译器将成为 FreeBSD 10 的默认 C/C 编译器,废弃使用 GPL 授权协议的 GCC,而 Clang 的授权协议是 BSD。 Clang 是一个 C 编写、基于 L…

HashMap中数组初始化的秘密

2019独角兽企业重金招聘Python工程师标准>>> 我们知道,在新建一个HashMap对象时,无论传的initialCapacity参数值为多少,最总HashMap中数组的长度始终为2的n次方,代码如下: static final int tableSizeFor(i…

PLSQL 安装+配置( Oracle数据库连接工具 )

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 1.找到免安装版本 PLSQL 解压到自己想放的位置 (比如 D:\ChengXu\PLSQL\PLSQL) 2.配置环境变量 : 系统变量…

什么是Nginx?为什么使用Nginx?

一、前言为毛要用nginx服务器代理,不直接用tomcat 7.0,还做多了一次接请求?这个是我想问的,公司的新项目是要用Nginxtomcat7jdk开发的,用户命名可以直接访问tomcat,为啥还要用Nginx?这货是个啥玩…

遵循五大设计理念 打造出色设计师

与其他设计不同,网页设计会随着时间的改变而不断改变着。因此,网页设计师需要不断的自我提升,了解最前沿的设计趋势以便能够设计出更加新颖的网站。 两年前,网页设计呈现出一片新的思维方式和新颖的设计趋势使得该领域彰显出一片…

shell符号

*: 通配符 *.c : c结尾的文件 *v : v结尾的文件 v* : v开头的文件转载于:https://www.cnblogs.com/runlgs/p/9685751.html

伪共享和缓存行填充,Java并发编程还能这么优化!

前言 关于伪共享的文章已经很多了,对于多线程编程来说,特别是多线程处理列表和数组的时候,要非常注意伪共享的问题。否则不仅无法发挥多线程的优势,还可能比单线程性能还差。随着JAVA版本的更新,再各个版本上减少伪共享…

mysql中like % %模糊查询

1,%:表示任意0个或多个字符。可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示。 比如 SELECT * FROM [user] WHERE u_name LIKE %三% 将会把u_name为“张三”,“张猫三…

Java中判断字符串是否为数字的五种方法

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 推荐使用第二个方法,速度最快。 方法一:用JAVA自带的函数 Java代码 public static boolean isNumeric(String…

慕学在线网0.4_xadmin后台管理

admin是基于Django开发的后台管理框架,方便,快捷,而且简单;   而xadmin就相当于admin的升级版,更加强大。    1、安装xadmin(源码安装方式)  教程 PS: - 卸载pip安装的xadminp…

从一次换机器的过程谈软硬件的分离

今天把在公司使用的计算机更换了一台,原来是Dell的780,换成了Dell的790,机箱的样子变化比较大,但是里面硬件的配置变换并不大,最明显的变化就在于CPU,其他像内存、硬盘等等的配置与原来的计算机基本上一致。…

知其所以然~redis的原子性

原子性 原子性是数据库的事务中的特性。在数据库事务的情景下,原子性指的是:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。 对于Redis而言&#xf…

JoinPoint的用法

JoinPoint 对象 JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象. 常用api: 方法名功能Signature getSignature();获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息…

解决 No projects are available for deployment to this server!

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 如题,今天在尝试部署从SVN上down下来的项目时,发现不能被tomcat识别成web项目!原因是SVN上down下来的…

地大信工成果快报

在成果快报投稿中,请注意以下几个问题:(1)成果信息一定要准确、全面,所有作者必须都要列出来,而不要出现et al. 这样的表述,通讯作者一定要用*号标注;(2)成果…

javaBean的命名规则

前段时间,写程序时,出了错误,竟然没有想到是自己属性命名的问题,哎~~~真是一定要注意规范呀,在这里我从网上找了些,规范作为参考 Sun 推荐的命名规范 1 ,类名要首字母大写,后面的单词…

volatile的应用

volatile,中文意思是不稳定的、反复无常的,用来修饰变量,和多线程、并发有关系。 Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行。 在多…