技术标签: springCloud
原文地址:
http://www.jianshu.com/p/b9af028efebb
导语:网上资料(尤其中文文档)对hystrix基础功能的解释比较笼统,看了往往一头雾水。为此,本文将通过若干demo,加入对官网How-it-Works的理解和翻译,力求更清晰解释hystrix的基础功能。所用demo均对官网How-To-Use进行了二次修改,见https://github.com/star2478/java-hystrix
Hystrix是Netflix开源的一款容错系统,能帮助使用者码出具备强大的容错能力和鲁棒性的程序。如果某程序或class要使用Hystrix,只需简单继承
HystrixCommand/HystrixObservableCommand
并重写run()/construct()
,然后调用程序实例化此class并执行execute()/queue()/observe()/toObservable()
。// HelloWorldHystrixCommand要使用Hystrix功能 public class HelloWorldHystrixCommand extends HystrixCommand { private final String name; public HelloWorldHystrixCommand(String name) { super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")); this.name = name; } // 如果继承的是HystrixObservableCommand,要重写Observable construct() @Override protected String run() { return "Hello " + name; } }
/* 调用程序对HelloWorldHystrixCommand实例化,执行execute()即触发HelloWorldHystrixCommand.run()的执行 */ String result = new HelloWorldHystrixCommand("HLX").execute(); System.out.println(result); // 打印出Hello HLX
pom.xml加上以下依赖。spring cloud也集成了hystrix,不过本文只介绍原生hystrix。
<dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>1.5.8</version> </dependency>
本文重点介绍的是Hystrix各项基础能力的用法及其效果,不从零介绍hystrix,要了解基础知识推荐官网wiki或民间blog
1、HystrixCommand vs HystrixObservableCommand
要想使用hystrix,只需要继承
HystrixCommand
或HystrixObservableCommand
,简单用法见上面例子。两者主要区别是:
前者的命令逻辑写在
run()
;后者的命令逻辑写在construct()
前者的
run()
是由新创建的线程执行;后者的construct()
是由调用程序线程执行前者一个实例只能向调用程序发送(emit)单条数据,比如上面例子中
run()
只能返回一个String结果;后者一个实例可以顺序发送多条数据,比如demo中顺序调用多个onNext()
,便实现了向调用程序发送多条数据,甚至还能发送一个范围的数据集2、4个命令执行方法
execute()
、queue()
、observe()
、toObservable()
这4个方法用来触发执行run()/construct()
,一个实例只能执行一次这4个方法,特别说明的是HystrixObservableCommand
没有execute()
和queue()
。4个方法的主要区别是:
execute()
:以同步堵塞方式执行run()
。以demo为例,调用execute()
后,hystrix先创建一个新线程运行run()
,接着调用程序要在execute()
调用处一直堵塞着,直到run()
运行完成
queue()
:以异步非堵塞方式执行run()
。以demo为例,一调用queue()
就直接返回一个Future对象,同时hystrix创建一个新线程运行run()
,调用程序通过Future.get()
拿到run()
的返回结果,而Future.get()
是堵塞执行的
observe()
:事件注册前执行run()/construct()
。以demo为例,第一步是事件注册前,先调用observe()
自动触发执行run()/construct()
(如果继承的是HystrixCommand
,hystrix将创建新线程非堵塞执行run()
;如果继承的是HystrixObservableCommand
,将以调用程序线程堵塞执行construct()
),第二步是从observe()
返回后调用程序调用subscribe()
完成事件注册,如果run()/construct()
执行成功则触发onNext()
和onCompleted()
,如果执行异常则触发onError()
toObservable()
:事件注册后执行run()/construct()
。以demo为例,第一步是事件注册前,一调用toObservable()
就直接返回一个Observable<String>
对象,第二步调用subscribe()
完成事件注册后自动触发执行run()/construct()
(如果继承的是HystrixCommand
,hystrix将创建新线程非堵塞执行run()
,调用程序不必等待run()
;如果继承的是HystrixObservableCommand
,将以调用程序线程堵塞执行construct()
,调用程序等待construct()
执行完才能继续往下走),如果run()/construct()
执行成功则触发onNext()
和onCompleted()
,如果执行异常则触发onError()
3、fallback(降级)
使用fallback机制很简单,继承
HystrixCommand
只需重写getFallback()
,继承HystrixObservableCommand
只需重写resumeWithFallback()
,比如HelloWorldHystrixCommand
加上下面代码片段:@Override protected String getFallback() { return "fallback: " + name; }
fallback实际流程是当
run()/construct()
被触发执行时或执行中发生错误时,将转向执行getFallback()/resumeWithFallback()
。结合下图,4种错误情况将触发fallback:
非HystrixBadRequestException异常:以demo为例,当抛出HystrixBadRequestException时,调用程序可以捕获异常,没有触发
getFallback()
,而其他异常则会触发getFallback()
,调用程序将获得getFallback()
的返回
run()/construct()
运行超时:以demo为例,使用无限while循环或sleep模拟超时,触发了getFallback()
熔断器启动:以demo为例,我们配置10s内请求数大于3个时就启动熔断器,请求错误率大于80%时就熔断,然后for循环发起请求,当请求符合熔断条件时将触发
getFallback()
。更多熔断策略见下文线程池/信号量已满:以demo为例,我们配置线程池数目为3,然后先用一个for循环执行
queue()
,触发的run()
sleep 2s,然后再用第2个for循环执行execute()
,发现所有execute()
都触发了fallback,这是因为第1个for的线程还在sleep,占用着线程池所有线程,导致第2个for的所有命令都无法获取到线程![]()
来自hystrix github wiki调用程序可以通过
isResponseFromFallback()
查询结果是由run()/construct()
还是getFallback()/resumeWithFallback()
返回的4、隔离策略
hystrix提供了两种隔离策略:线程池隔离和信号量隔离。hystrix默认采用线程池隔离。
线程池隔离:不同服务通过使用不同线程池,彼此间将不受影响,达到隔离效果。以demo为例,我们通过andThreadPoolKey配置使用命名为
ThreadPoolTest
的线程池,实现与其他命名的线程池天然隔离,如果不配置andThreadPoolKey则使用withGroupKey配置来命名线程池信号量隔离:线程隔离会带来线程开销,有些场景(比如无网络请求场景)可能会因为用开销换隔离得不偿失,为此hystrix提供了信号量隔离,当服务的并发数大于信号量阈值时将进入fallback。以demo为例,通过
withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
配置为信号量隔离,通过withExecutionIsolationSemaphoreMaxConcurrentRequests
配置执行并发数不能大于3,由于信号量隔离下无论调用哪种命令执行方法,hystrix都不会创建新线程执行run()/construct()
,所以调用程序需要自己创建多个线程来模拟并发调用execute()
,最后看到一旦并发线程>3,后续请求都进入fallback5、熔断机制
熔断机制相当于电路的跳闸功能,举个栗子,我们可以配置熔断策略为当请求错误比例在10s内>50%时,该服务将进入熔断状态,后续请求都会进入fallback。
以demo为例,我们通过
withCircuitBreakerRequestVolumeThreshold
配置10s内请求数超过3个时熔断器开始生效,通过withCircuitBreakerErrorThresholdPercentage
配置错误比例>80%时开始熔断,然后for循环执行execute()
触发run()
,在run()
里,如果name
是小于10的偶数则正常返回,否则超时,通过多次循环后,超时请求占所有请求的比例将大于80%,就会看到后续请求都不进入run()
而是进入getFallback()
,因为不再打印"running run():" + name
了。除此之外,hystrix还支持多长时间从熔断状态自动恢复等功能,见下文附录。
6、结果cache
hystrix支持将一个请求结果缓存起来,下一个具有相同key的请求将直接从缓存中取出结果,减少请求开销。要使用hystrix cache功能,第一个要求是重写
getCacheKey()
,用来构造cache key;第二个要求是构建context,如果请求B要用到请求A的结果缓存,A和B必须同处一个context。通过HystrixRequestContext.initializeContext()
和context.shutdown()
可以构建一个context,这两条语句间的所有请求都处于同一个context。以demo的
testWithCacheHits()
为例,command2a、command2b、command2c同处一个context,前两者的cache key都是2HLX
(见getCacheKey()
),所以command2a执行完后把结果缓存,command2b执行时就不走run()
而是直接从缓存中取结果了,而command2c的cache key是2HLX1
,无法从缓存中取结果。此外,通过isResponseFromCache()
可检查返回结果是否来自缓存。7、合并请求collapsing
hystrix支持N个请求自动合并为一个请求,这个功能在有网络交互的场景下尤其有用,比如每个请求都要网络访问远程资源,如果把请求合并为一个,将使多次网络交互变成一次,极大节省开销。重要一点,两个请求能自动合并的前提是两者足够“近”,即两者启动执行的间隔时长要足够小,默认为10ms,即超过10ms将不自动合并。
以demo为例,我们连续发起多个queue请求,依次返回f1~f6共6个Future对象,根据打印结果可知f1~f5同处一个线程,说明这5个请求被合并了,而f6由另一个线程执行,这是因为f5和f6中间隔了一个sleep,超过了合并要求的最大间隔时长。
附录:各种策略配置
根据http://hot66hot.iteye.com/blog/2155036 整理而得。
- HystrixCommandProperties
/* --------------统计相关------------------*/ // 统计滚动的时间窗口,默认:5000毫秒(取自circuitBreakerSleepWindowInMilliseconds) private final HystrixProperty metricsRollingStatisticalWindowInMilliseconds; // 统计窗口的Buckets的数量,默认:10个,每秒一个Buckets统计 private final HystrixProperty metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow // 是否开启监控统计功能,默认:true private final HystrixProperty metricsRollingPercentileEnabled; /* --------------熔断器相关------------------*/ // 熔断器在整个统计时间内是否开启的阀值,默认20。也就是在metricsRollingStatisticalWindowInMilliseconds(默认10s)内至少请求20次,熔断器才发挥起作用 private final HystrixProperty circuitBreakerRequestVolumeThreshold; // 熔断时间窗口,默认:5秒.熔断器中断请求5秒后会进入半打开状态,放下一个请求进来重试,如果该请求成功就关闭熔断器,否则继续等待一个熔断时间窗口 private final HystrixProperty circuitBreakerSleepWindowInMilliseconds; //是否启用熔断器,默认true. 启动 private final HystrixProperty circuitBreakerEnabled; //默认:50%。当出错率超过50%后熔断器启动 private final HystrixProperty circuitBreakerErrorThresholdPercentage; //是否强制开启熔断器阻断所有请求,默认:false,不开启。置为true时,所有请求都将被拒绝,直接到fallback private final HystrixProperty circuitBreakerForceOpen; //是否允许熔断器忽略错误,默认false, 不开启 private final HystrixProperty circuitBreakerForceClosed; /* --------------信号量相关------------------*/ //使用信号量隔离时,命令调用最大的并发数,默认:10 private final HystrixProperty executionIsolationSemaphoreMaxConcurrentRequests; //使用信号量隔离时,命令fallback(降级)调用最大的并发数,默认:10 private final HystrixProperty fallbackIsolationSemaphoreMaxConcurrentRequests; /* --------------其他------------------*/ //使用命令调用隔离方式,默认:采用线程隔离,ExecutionIsolationStrategy.THREAD private final HystrixProperty executionIsolationStrategy; //使用线程隔离时,调用超时时间,默认:1秒 private final HystrixProperty executionIsolationThreadTimeoutInMilliseconds; //线程池的key,用于决定命令在哪个线程池执行 private final HystrixProperty executionIsolationThreadPoolKeyOverride; //是否开启fallback降级策略 默认:true private final HystrixProperty fallbackEnabled; // 使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作.默认:true private final HystrixProperty executionIsolationThreadInterruptOnTimeout; // 是否开启请求日志,默认:true private final HystrixProperty requestLogEnabled; //是否开启请求缓存,默认:true private final HystrixProperty requestCacheEnabled; // Whether request caching is enabled.
- HystrixCollapserProperties
//请求合并是允许的最大请求数,默认: Integer.MAX_VALUE private final HystrixProperty maxRequestsInBatch; //批处理过程中每个命令延迟的时间,默认:10毫秒 private final HystrixProperty timerDelayInMilliseconds; //批处理过程中是否开启请求缓存,默认:开启 private final HystrixProperty requestCacheEnabled;
- HystrixThreadPoolProperties
/* 配置线程池大小,默认值10个. 建议值:请求高峰时99.5%的平均响应时间 + 向上预留一些即可 */ private final HystrixProperty corePoolSize; /* 配置线程值等待队列长度,默认值:-1 建议值:-1表示不等待直接拒绝,测试表明线程池使用直接决绝策略+ 合适大小的非回缩线程池效率最高.所以不建议修改此值。 当使用非回缩线程池时,queueSizeRejectionThreshold,keepAliveTimeMinutes 参数无效 */ private final HystrixProperty maxQueueSize;
参考文献
https://github.com/Netflix/Hystrix
https://github.com/Netflix/Hystrix/wiki/How-To-Use
http://hot66hot.iteye.com/blog/2155036
作者:star24
链接:http://www.jianshu.com/p/b9af028efebb
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
现在很多的电脑都是Win10系统,Win10系统电脑都有自带的便笺工具,便笺是一款记录软件,在平时工作生活中可以记录各种内容,记录的内容多了,使用的空间也在变少,有的人会进行整理,将不需要的删除优化使用的空间,有可能顺手将便笺删掉,便笺中记录的内容在某些地方还能用到,那么怎么去恢复呢?恢复后便笺记录的内容能找回么?在“HKEY_CURRENT_USERSoftwareMicrosoftWindow...
打印机打印后,总是显示正在删除怎么办?有什么办法可以解决?下面就给大家带来 打印机显示正在删除解决办法 ,一起来看看。方法一:删除打印机打印任务时,电脑提示正在删除,却一直没有显示删除。其实,打印任务可能已经被删除了,只是电脑没有显示而已。最简单的方法,关闭打印机,重新打印打印机电源。这时候再检查打印任务,就已经全部删除了。这是由于,当前系统下,某文件有可能正在被系统本身或是其他应用软件调用,而正...
电子邮件是Internet上最重要的应用之一,它提供了一种极为方便、快速的通讯方式。但是,很多网民都有过收发电子邮件失败的经历。下面笔者通过对E -mail收发失败的原因作详细的论述,来谈谈如何提高E-mail收发的成功率。 一、E-mail收发的一般过程 一般来说,E-mail的发信方式分为两种:一种是通过ISP或免费邮箱服务商提供的SMTP发信服务器中转的发信...
我允许自己在这里提问,因为我查找了关于我的问题该怎么做,但没有找到任何有用的信息。将页面另存为.html并上传到ftp我有一个网页,用户可以在其中修改信息,如文本,图像等,我想添加一个按钮,将页面保存为当前状态的.html(重新加载密码重置所有内容)并上传它在一个FTP上,所以他们可以在线访问它。此时,我知道如何使用js .innerHTML获取所有html内容,以及如何使用php将文件发送到ft...
以前工作的公司,也是用微服务架构,使用的是很简陋的自己封装的微服务框架,Apache CXF + Eureka,但没有实现服务降级和熔点的思想。一个典型的问题是,A服务依赖B服务,B服务依赖C服务,然而C服务因为数据库或其他原因的导致请求线程卡死,这样导致B服务等待C,A服务等待B,用户看到页面空白(A服务渲染)。这还不是最糟糕的,最糟糕的是并发量上去,C拖死B,B拖死A,A、B、C都死翘翘了,最...
step1,修改“C:\Program Files\Borland\Delphi7\Bin”的权限(右击上面的目录-》属性-》安全-》编辑-》修改后确定退出),赋予于users组modify权限; step2,修改“C:\Program Files\Borland\Delphi7\Projects”的权限(右击上面的目录-》属性-》安全-》编辑-》修改后确定退出),赋予于users组mo...
TCP协议(“传输控制协议(Transmission Control Protocol”). )是当今使用最广泛的协议之一,首先我们要明确TCP协议是一个(1)有连接(2)可靠传输(3)面向字节流的一个协议。现在就来细数以下他具有的几大特点。1. 确认应答机制这是TCP协议可靠性的核心机制,接收方在收到发送方发出的数据时返回一个ACK,表示我已经收到数据了,然后,发送方在接受到接收方发送的AC...
其实,MyBatis 没有实现多对多级联,这是因为多对多级联可以通过两个一对多级联进行替换。例如,一个订单可以有多种商品,一种商品可以对应多个订单,订单与商品就是多对多的级联关系,使用一个中间表(订单记录表)就可以将多对多级联转换成两个一对多的关系。下面以订单和商品(实现“查询所有订单以及每个订单对应的商品信息”的功能)为例讲解多对多级联查询。1)创建数据表订单表在前面已创建,这里需要创建商品表 ...
前言接前面介绍的Python Web框架2020年最流行Python web开发框架(上) ,Django作为最经典的Web框架,被很多世界顶级网站应用。以下就逐一介绍使用Django构建的网站,还将分析为什么这些网站会用Django。这样不仅让你知道Python在互联网的重要作用,还将启发您在自己的项目中应用的内容。首先,介绍一系列视频音频网站,之所以介绍他们,是要破除某些觉得Python不能做...
因为php版本高,出现的问题类似如下: Notice:Undefinedindex:admin_nameinF:\wamp\www\XL\admin\index.phponline16 刚开始不以为然,只是在php文件中在这句话前边加上@标识符,感觉又很繁琐。但是最重...
接触Qt断断续续有些时间了,总看了一堆的文章说信号槽的概念,心里就想骂人,做为一个初学者,最重要的就是怎么写代码,写代码写多了,再去看理论,有时水到渠成的就明白那些理论了。但所有讲信号槽的都把一堆信号槽的好处说一通,把MFC的消息机制贬一通。具体代码应该怎么实现信号槽轻飘飘的就忽略过去了。直接开始吧!信号槽是为了实现两个对象之间的通信机制,说白了就是比如一个按钮对象点击了一下想告诉主界面并让主界面...
AMD电脑的VMware安装macOS 最后出现的错误,网上找了许多解决办法,最后依靠这个解决了我们需要在虚拟机运行之前打开虚拟机安装目录自动生成的macOS xxxx(你选择安装的版本号).vmx只需要在末尾添加cpuid.0.eax = "0000:0000:0000:0000:0000:0000:0000:1011"cpuid.0.ebx = "0111:0101:0110:1110:0110:0101:0100:0111"cpuid.0.ecx = "0110:1100:0