为什么需要Hystrix断路器
在理想状态下,一个应用依赖的服务都是健康可用的,我们可以正常的处理所有的请求
当某一个服务出现延迟时,所有的请求都阻塞在依赖的服务Dependency I
当依赖I 阻塞时,大多数服务器的线程池就出现阻塞(BLOCK),影响整个线上服务的稳定性
在复杂的分布式架构的应用程序有很多的依赖,都会不可避免地在某些时候失败。高并发的依赖失败时如果没有隔离措施,当前应用服务就有被拖垮的风险(雪崩现象)
解决方案
对依赖做隔离,Hystrix就是处理依赖隔离的框架,同时也是可以帮我们做依赖服务的治理和监控.。
当我们使用了Hystrix时,Hystrix将所有的外部调用都封装成一个HystrixCommand或者 HystrixObservableCommand对象,这些外部调用将会在一个独立的线程中运行。
我们可以将出现 问题的服务通过熔断、降级等手段隔离开来,这样不影响整个系统的主业务
Hystrix是保证微服务群健壮框架,做了隔离,熔断,降级等操作.最终达到不会由于某一个服务出问题而导致雪崩现象,让整体群死掉
Hystrix简介
Hystrix是国外知名的视频网站Netflix所开源的非常流行的高可用架构框架。Hystrix能够完美的解决分布式系统架构中打造高可用服务面临的一系列技术难题。
Hystrix,具有自我保护的能力。hystrix 通过如下机制来解决雪崩效应问题:
资源隔离(限流):包括线程池隔离和信号量隔离(计数器),限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
融断:当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。
降级机制:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。 缓存:提供了请求缓存、请求合并实现。
原理分析-命令模式
Hystrix使用命令模式(继承HystrixCommand(隔离)类)来包裹具体的服务调用逻辑(run方法), 并在命令模式中添加了服务调用失败后的降级逻辑(getFallback).
同时我们在Command的构造方法中可以定义当前服务线程池和熔断器的相关参数
public class Sercixe1HystrixConmmand extends HystrixCommand<Response>{
private Service1 service;
private Request request;
public Service1HystricCommand(Service1 service,Request request){
supper(
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("Service1ThreadPool")
.andCommandKey(HystrixCommandKey.Factory.asKey("Service1query")
.andThreadPoolKey(HystricThreadPoolKey.Factory.asKey("service1ThreadPool")
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(20)//服务器线程池数量
)
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withCircuitBreakerErrorThresholdPercentage(60)//熔断器关闭到打开的阀值
.withCircuitBreakerSleepWindowInMilliseconds(3000)//熔断器打开段关闭的时间窗长度
)
this.service = service;
this.request = request;
);
}
}
在使用了Command模式构建了服务对象之后, 服务便拥有了熔断器和线程池的功能.
资源隔离&限流
(1)线程池隔离模式:
使用一个线程池来存储当前请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求先入线程池队列。这种方式要为每个依赖服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池队里慢慢处理)
(2)信号量隔离模式:
使用一个原子计数器(或信号量)记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃该类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)
线程池隔离 | 信号量隔离 | |
---|---|---|
线程 | 与调度线程非相同线程 | 与调用线程相同(jetty线程) |
开销 | 排队、调度、上下文开销等 | 无线程切换,开销低 |
异步 | 支持 | 不支持 |
并发支持 | 支持(最大线程池大小) | 支持(最大信号量上限) |
服务熔断
正常情况下,断路器处于关闭状态(Closed),如果调用持续出错或者超时,电路被打开进入熔断状态(Open),后续一段时间内的所有调用都会被拒绝(Fail Fast),一段时间以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试, 如果调用仍然失败,则回到熔断状态如果调用成功,则回到电路闭合状态
熔断的参数配置
Hystrix提供了如下的几个关键参数,来对一个熔断器进行配置:
circuitBreaker.requestVolumeThreshold
//滑动窗口的大小,默认为20
circuitBreaker.sleepWindowInMilliseconds
//过多长时间,熔断器再次检测是否开启,默认为5000,即5s钟
circuitBreaker.errorThresholdPercentage
//错误率,默认50%
3个参数放在一起,所表达的意思就是:
每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。
直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。
服务降级
有了熔断,就得有降级。所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。
这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。