通过配置中心可以进行人工降级,而我们也需要根据服务的超时时间进行自动降级,下面主要介绍如何使用Hystrix进行降级,关于其他一些配置,可以看上一篇文章:
基于Hystrix实现线程隔离技术-运用线程池
1. 使用Hystrix进行降级
如何使用可以看以下代码:
public class HystrixProblemServiceCommand extends HystrixCommand<List<Problem>> {
// 组名
private static final String GROUP_KEY = "qa";
// 命令标识名
private static final String COMMAND_KEY = "query";
// 线程池名
private static final String THREADPOOL_KEY = "qa-pool";
@Autowired
private ProblemService problemService;
public HystrixProblemServiceCommand() {
super(setter());
}
private static Setter setter() {
// 服务分组
HystrixCommandGroupKey hystrixCommandGroupKey = HystrixCommandGroupKey.Factory.asKey(GROUP_KEY);
// 服务唯一标识
HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(COMMAND_KEY);
// 线程池名称
HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(THREADPOOL_KEY);
// 线程池配置
HystrixThreadPoolProperties.Setter thresholdConfig = HystrixThreadPoolProperties.Setter()
.withCoreSize(10) // 核心线程池大小
.withKeepAliveTimeMinutes(5) // 空闲线程存活时间
.withMaxQueueSize(Integer.MAX_VALUE) // 线程池队列大小
.withQueueSizeRejectionThreshold(1000); //限定当前队列大小
// 命令属性配置,设置隔离策略为线程隔离
HystrixCommandProperties.Setter isolationStrategy = HystrixCommandProperties.Setter()
// 设置隔离为线程隔离
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
// 设置启用降级处理
.withFallbackEnabled(true)
// 设置如果请求超过了并发信号量限制,则不再尝试调用getFallback方法,而是快速失败
.withFallbackIsolationSemaphoreMaxConcurrentRequests(100)
// 隔离策略为THREAD时,当执行线程执行超时时,是否进行中断处理,设置为true
.withExecutionIsolationThreadInterruptOnFutureCancel(true)
//当隔离策略为THREAD时,当执行线程执行超时时,是否进行中断处理,默认为true。
.withExecutionIsolationThreadInterruptOnTimeout(true)
//是否启用执行超时机制,默认为true。
.withExecutionTimeoutEnabled(true)
// 执行超时时间,默认为1000毫秒,如
.withExecutionTimeoutInMilliseconds(1000);
/*return HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(GROUP_KEY))
.andCommandKey(HystrixCommandKey.Factory.asKey(COMMAND_KEY))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(THREADPOOL_KEY))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD));*/
return HystrixCommand.Setter.withGroupKey(hystrixCommandGroupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey).andThreadPoolPropertiesDefaults(thresholdConfig).andCommandPropertiesDefaults(isolationStrategy);
}
@Override
protected List<Problem> run() throws Exception {
//可以抛出异常或者模拟超时
return problemService.findAll();
}
@Override
protected List<Problem> getFallback() {
// 降级方法
return new ArrayList<>();
}
public ProblemService getProblemService() {
return problemService;
}
public void setProblemService(ProblemService problemService) {
this.problemService = problemService;
}
}
整体执行流程如下:
首先,Command会调用run方法,如果run方法超时或者抛出异常,且启用了降级处理,则调用getFallback方法进行降级。
而降级处理主要有两部分处理: HystrixCommandProperties配置和getFallback降级处理方法。
HystrixCommandProperties配置:
withFallbackEnabled: 是否启用降级处理,如果启用了,则在超时或异常时调用getFallback进行降级处理,默认为开启。
withFallbacklsolationSemaphoreMaxConcurrentRequests: fall back方法的信号量配置,配置getFallback方法并发请求的信号量,如果请求超过了并发信号量限制,则不再尝试调用getFallback方法,而是快速失败,默认信号量为10。
withExecutionlsolationThreadlnterruptOnFutureCancel : 隔离策略为THREAD时,当执行线程执行超时时,是否进行中断处理,即Future#cancel(true)处理,默认为false。
withExecutionlsolationThreadlnterruptOnTimeout:当隔离策略为THREAD时,当执行线程执行超时时,是否进行中断处理,默认为true。跟上一条配置的区别在于执行是否有返回值。
withExecutionTimeoutEnabled:是否启用执行超时机制,默认为true。
withExecutionTimeoutlnMilliseconds:执行超时时间,默认为1000毫秒,如果命令是线程隔离,且配置了executionlsolationThreadlnterruptOnT1meout = true, 则执行线程将执行中断处理。
当开启了降级处理,run方法超时或者异常时将会调用getFallback处理,使用getFallback时需要注意以下几点:
• 其最大并发数受fallbackisolationSemaphoreMaxConcurrentRequests控制,因此,如果失败率非常高,则要重新配置该参数,如果最大并发数超了该配置,则不会再执行getFallback, 而是快速失败,抛出如"HystrixRuntimeException: GetStockServiceCommand fallback execution rejected"的异常。
• 该方法不能进行网络调用(HTTP调用其他服务),应该只是使用缓存的数据,或者静态数据(如我们的问题方法返回获取失败)。
• 如果必须走网络调用,则应该在getFallback方法中调用另 一 个Command实现,通过Command可以有降级和熔断机制保护应用,而getFallback只有fallbacklsolationSemaphoreMaxConcurrentRequests参数控制最大并发数。
在处理业务代码时,可以使用以下方法,判断执行的状态:
• isResponseTimedOut: 响应是否超时了。
• isFailedExecution: 执行是否失败了,如抛出了异常。
• getFailedExecutionException: 获取失败后的执行异常,即run方法抛出的异常。
• isResponseFromFallback:是否是getFallback返回的响应。
2.使用Hystrix实现熔断
熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。
这种牺牲局部,保全整体的措施就叫做熔断。
对于熔断机制的实现,Hystrix设计了三种状态:
1.熔断关闭状态(Closed)服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制。
2.熔断开启状态(Open)在固定时间窗口内(Hystrix默认是10秒),接口调用出错比率达到一个阈值(Hystrix默认为50%),会进入熔断开启状态。进入熔断状态后,后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法。
3.半熔断状态(Half-Open)在进入熔断开启状态一段时间之后(Hystrix默认是5秒),熔断器会进入半熔断状态。所谓半熔断就是尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断关闭状态。
Hystrix提供了熔断实现,熔断后会自动降级处理,如下图所示:
image.png
如何配置?
// 命令属性配置,设置隔离策略为线程隔离
HystrixCommandProperties.Setter isolationStrategy = HystrixCommandProperties.Setter()
// 设置隔离为线程隔离
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
// 设置启用降级处理
.withFallbackEnabled(true)
// 设置如果请求超过了并发信号量限制,则不再尝试调用getFallback方法,而是快速失败
.withFallbackIsolationSemaphoreMaxConcurrentRequests(100)
// 隔离策略为THREAD时,当执行线程执行超时时,是否进行中断处理,设置为true
.withExecutionIsolationThreadInterruptOnFutureCancel(true)
//当隔离策略为THREAD时,当执行线程执行超时时,是否进行中断处理,默认为true。
.withExecutionIsolationThreadInterruptOnTimeout(true)
//是否启用执行超时机制,默认为true。
.withExecutionTimeoutEnabled(true)
// 执行超时时间,默认为1000毫秒,如
.withExecutionTimeoutInMilliseconds(1000)
// 是否开启熔断机制
.withCircuitBreakerEnabled(true)
// 是否强制关闭熔断开关
.withCircuitBreakerForceClosed(false)
// 是否强制打开熔断开关
.withCircuitBreakerForceOpen(false)
// 一 个采样时间窗口内,失败率超过该配置,则自动打开熔断开关实现降级处理,
// 即快速失败。默认配置下采样周期为10s, 失败率为50% 。
.withCircuitBreakerErrorThresholdPercentage(50)
// 开关闭合的情况下,在进行失败率判断之前,一个采样周期内必须进行至少N个请求才能进行采样统计,
// 目的是有足够的采样使得失败率计算正确,默认为20 。
.withCircuitBreakerRequestVolumeThreshold(20)
// 熔断后的重试时间窗口,且在该时间窗口内只允许一 次重试。
//如果重试成功,则将重置H ealth采样统计并闭合熔断开关实现快速恢复
//否则熔断开关还是打开状态,执行快速失败。
.withCircuitBreakerSleepWindowInMilliseconds(5000);
熔断后将降级调用getFallback 进行处理.会通过commond的如下方法判断:
HystrixProblemServiceCommand hystrixProblemServiceCommand = new HystrixProblemServiceCommand();
hystrixProblemServiceCommand.setProblemService(problemService);
// 熔断开关是否打开
hystrixProblemServiceCommand.isCircuitBreakerOpen();
hystrixProblemServiceCommand.isResponseShortCircuited();
待续。。。
网友评论