Hystrix实战之实现降级和熔断

2020-04-23  本文已影响0人  先生zeng

通过配置中心可以进行人工降级,而我们也需要根据服务的超时时间进行自动降级,下面主要介绍如何使用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();

待续。。。

上一篇下一篇

猜你喜欢

热点阅读