概念
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
"断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了敌障在分布式系统中的蔓延,乃至雪崩。
同技术:Sentinel
应用
pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
主启动类上加上
@EnableCircuitBreaker //启用断路器
@HystrixCommand 可针对单个接口进行个性化的服务降级或熔断处理
属性 fallbackMethod,commandProperties
@RequestMapping("")
@HystrixCommand(fallbackMethod="errorCallBack",commandProperties={
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="")
})
public String test(){
return "程序正常";
}
public String errorCallBack(){
return "程序出错";
}
@FeignClient fallbackFactory/fallback 属性
例:@FeignClient(name = “TEST”, fallbackFactory = TestFacadeFallback.class)
实现FallbackFactory 相较于fallback属性 ,可以打印熔断或者降级原因
@Component
public class TestFacadeFallback implements FallbackFactory<TestFacade>{
private static final Logger log = LoggerFactory.getLogger(TestFacadeFallback.class);
@Override
public TestFacade create(Throwable cause) {
log.error("testFacade error:"+cause.getMessage(),cause);
return new TestFacade() {
@Override
public String request() {
return "熔断";
}
};
}
}
服务降级触发场景:
程序异常
超时
服务熔断触发服务降级
线程池/信号量已满
熔断机制概述
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。
当检测到该节点微服务调用响应正常后,恢复调用链路。
在Spring Cloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,
当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是@HystrixCommand。
熔断器最开始处于closed状态,一旦检测到错误到达一定阈值,便转为open状态;
这时候会有个 reset timeout,到了这个时间了,会转移到half open状态,尝试放行一部分请求到后端,一旦检测成功且失败率降低便回归到closed状态,即恢复服务;
涉及到断路器的三个重要参数:快照时间窗、请求总数阀值、错误百分比阀值。
1:快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。
2∶请求总数阀值:在快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。
3∶错误百分比阀值:当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阀值情况下,这时候就会将断路器打开。
—代码—
@HystrixCommand(fallbackNethod = "testCircuitBreaker_fallback" //服务降级
, commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true" // 开启熔断
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //在配置时间窗口内达到此数量的失败后,进行短路
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000") //时间窗口 短路多久以后开始尝试是否恢复
,@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage" ,value = "60"), //出错百分比阈值,当达到此阈值后,开始短路
})
public string testcircuitBreaker(@Pathvariable("id") Integer id){
if(id < o){
throw new RuntimeException("id不能负数");
}
return "调用成功,id: " + id;
}
public string testCircuitBreaker_fallback(@Pathvariable("id") Integer
id)
{
return "id不能为负数"+id;
}
断路器打开之后
1:再有请求调用的时候,将不会调用主逻辑,而是直接调用降级fallback、通过断路器
实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响
应延迟的效果。
2:原来的主逻辑要如何恢复呢?
对于这一问题,hystrix也为我们实现了自动恢复功能。
当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,当休眠时间窗到期,断路器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。
熔断/降级策略:
@HystrixCommand
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;