微服务熔断、降级——Hystrix

一、概述

1、服务雪崩

分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应
在这里插入图片描述
雪崩效应常见场景

1)硬件故障:如服务器宕机,机房断电,光纤被挖断等。
2)流量激增:如异常流量,重试加大流量等。
3)缓存穿透:一般发生在应用重启,所有缓存失效时,以及短时间内大量缓存失效时。大量的缓存不命中,使请求直击后端服务,造成服务提供者超负荷运行,引起服务不可用。
4)程序 BUG:如程序逻辑导致内存泄漏,JVM 长时间 FullGC 等。 同步等待:服务间采用同步调用模式,同步等待造成的资源耗尽。

雪崩效应应对策略

针对造成雪崩效应的不同场景,可以使用不同的应对策略,没有一种通用所有场景的策略,参考如下:

1)硬件故障:多机房容灾、异地多活等。
2)流量激增:服务自动扩容、流量控制(限流、关闭重试)等。 缓存穿透:缓存预加载、缓存异步加载等。
3)程序 BUG:修改程序 bug、及时释放资源等。
4)同步等待:资源隔离、MQ 解耦、不可用服务调用快速失败等。资源隔离通常指不同服务调用采用不同的线程池;不可用服务调用快速失败一般通过熔断器模式结合超时机制实现。

综上所述,如果一个应用不能对来自依赖的故障进行隔离,那该应用本身就处在被拖垮的风险中。
因此,为了构建稳定、可靠的分布式系统,我们的服务应当具有自我保护能力,当依赖服务不可用时,当前服务启动自我保护功能,从而避免发生雪崩效应

2、Hystrix

(1)Hystrix 是什么

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix 能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性
"断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩

(2)Hystrix 设计目标:

对来自依赖的延迟和故障进行防护和控制——这些依赖通常都是通过网络访问的
阻止故障的连锁反应
快速失败并迅速恢复
回退并优雅降级
提供近实时的监控与告警

(3)Hystrix 遵循的设计原则:

防止任何单独的依赖耗尽资源(线程)
过载立即切断并快速失败,防止排队
尽可能提供回退以保护用户免受故障
使用隔离技术(例如隔板,泳道和断路器模式)来限制任何一个依赖的影响
通过近实时的指标,监控和告警,确保故障被及时发现
通过动态修改配置属性,确保故障及时恢复
防止整个依赖客户端执行失败,而不仅仅是网络通信

(4)Hystrix 如何实现这些设计目标?

使用命令模式将所有对外部服务(或依赖关系)的调用包装在 HystrixCommand 或 HystrixObservableCommand 对象中,并将该对象放在单独的线程中执行;
每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)
记录请求成功,失败,超时和线程拒绝。
服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求
请求失败,被拒绝,超时或熔断时执行降级逻辑
近实时地监控指标和配置的修改。

二、服务熔断、降级与限流

1、服务降级——丢车保帅

服务降级是指当服务器压力剧增的情况下,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和服务的请求,而直接返回一个提前准备好的 fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但释放了服务器资源以保证核心业务正常运作或高效运作,保证了整个系统的稳定性和可用性。说白了,就是尽可能的把系统资源让给优先级高的服务。
资源有限,而请求是无限的。如果在并发高峰期,不做服务降级处理,一方面肯定会影响整体服务的性能,严重的话可能会导致宕机某些重要的服务不可用。所以,一般在高峰期,为了保证核心功能服务的可用性,都要对某些服务降级处理。比如当双 11 活动时,把交易无关的服务统统降级,如查看蚂蚁深林,查看历史订单等等。

(1)服务降级主要用于什么场景呢?

当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,可以将一些不重要或不紧急的服务或任务进行服务的延迟使用 或暂停使用。
降级的方式可以根据业务来,可以延迟服务,比如延迟给用户增加积分,只是放到一个缓存中,等服务平稳之后再执行;或者在粒度范围内关闭服务,比如关闭相关文章的推荐。

(2)实现服务降级需要考虑几个问题

1)那些服务是核心服务,哪些服务是非核心服务
2)那些服务可以支持降级,那些服务不能支持降级,降级策略是什么
3)除服务降级之外是否存在更复杂的业务放通场景,策略是什么?

(3)降级分类

1)超时降级:主要配置好超时时间和超时重试次数和机制,并使用异步机制探测回复情况
2)失败次数降级:主要是一些不稳定的 api,当失败调用次数达到一定阀值自动降级,同样要使用异步机制探测回复情况
3)故障降级:比如要调用的远程服务挂掉了(网络故障、DNS故障、http服务返回错误的状态码、rpc服务抛出异常),则可以直接降级。降级后的处理方案有:默认值(比如库存服务挂了,返回默认现货)、兜底数据(比如广告挂了,返回提前准备好的一些静态页面)、缓存(之前暂存的一些缓存数据)
4)限流降级:秒杀或者抢购一些限购商品时,此时可能会因为访问量太大而导致系统崩溃,此时会使用限流来进行限制访问量,当达到限流阀值,后续请求会被降级;降级后的处理方案可以是:排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)。

2、服务熔断

降级一般而言指的是我们自身的系统出现了故障而降级。而熔断一般是指依赖的外部接口出现故障的情况断绝和外部接口的关系
在微服务架构中,微服务之间的数据交互通过远程调用完成,微服务A调用微服务 B 和微服务 C,微服务B和微服务 C 又调用其它的微服务,此时如果链路上某个微服务的调用响应时间过长或者不可用,那么对微服务 A 的调用就会占用越来越多的系统资源,进而引起系统崩溃,导致“雪崩效应”。
服务熔断是应对雪崩效应的一种微服务链路保护机制。例如在高压电路中,如果某个地方的电压过高,熔断器就会熔断,对电路进行保护。同样,在微服务架构中,熔断机制也是起着类似的作用。当调用链路的某个微服务不可用或者响应时间太长时,会进行服务熔断,不再有该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路

服务熔断解决如下问题:
1)当所依赖的对象不稳定时,能够起到快速失败的目的
2)快速失败后,能够根据一定的算法动态试探所依赖对象是否恢复

3、服务限流限流

上面说的两个算是请求过来我们都受理了,这个限流就更狠了,直接跟请求说对不起再见!也就是系统规定了多少承受能力,只允许这么些请求能过来,其他的请求不对其进行处理

一般限制的指标有:请求总量或某段时间内请求总量。

1)请求总量:比如秒杀的,秒杀100份产品,我就放5000名进来,超过的直接拒绝请求了。

2)某段时间内请求总量:比如规定了每秒请求的峰值是1W,这一秒内多的请求直接拒绝了。咱们下一秒再见。

熔断 VS 降级

(1)相同点:

目标一致 都是从可用性和可靠性出发,为了防止系统崩溃;

用户体验类似 最终都让用户体验到的是某些功能暂时不可用;

(2)不同点:

1)触发原因不同:服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
2)实现方式不同:服务降级具有代码侵入性(由控制器完成/或自动降级),熔断一般称为自我熔断。

总结

(1)限流:限制并发的请求访问量,超过阈值则拒绝;
(2)降级:服务分优先级,牺牲非核心服务(不可用),保证核心服务稳定;从整体负荷考虑;
(3)熔断:依赖的下游服务故障触发熔断,避免引发本系统崩溃;系统自动执行和恢复

三、Hystrix 进行服务降级

服务降级就是指服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示 fallback。

哪些情况会触发降级:

1)程序运行异常
2)超时
3)服务熔断触发服务降级,
4)线程池/信号量打满也会导致服务降级;

服务降级分为服务端降级和客户端降级,好比一双筷子,你可以夹肉,也可以夹菜,不过一般是用来在客户端降级使用,具体情况具体分析使用。

添加依赖

	<!--使用 openfeign 进行服务调用-->
	<!--openfeign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
    <!--hystrix-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

1、服务端服务降级

注:服务端指的是被调用的一方。

(1)使用 @HystrixCommand 在被调用的服务端设置兜底的 fallback 降级方法

@Service
public class ProvideHystrixService {
    
    
 
    /**
     * 成功访问
     */
    public String getOk(Integer id) {
    
    
        return "线程池:" + Thread.currentThread().getName() + " ID:" + id + "\t 访问成功";
    }
 
    /**
     * 访问超时
     */
    @HystrixCommand(fallbackMethod ="paymentFallback_handler", commandProperties = {
    
     @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "5000") })
    public String getTimeout(Integer id) {
    
    
        int timeout = 6;
        try {
    
    
            TimeUnit.SECONDS.sleep(timeout);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + " ID:" + id + "\t 访问超时,超时时间(秒):" + timeout;
    }
 
 	// 兜底的 fallback 方法
    public String paymentFallback_handler(Integer id){
    
    
        return "线程池:" + Thread.currentThread().getName() + " paymentFallback_handler---ID:" + id + "\t ";
    }
}

@HystrixCommand 注解是方法级别的,在你需要捕获的方法上加上注解。fallbackMethod 属性指定了捕获异常时需要执行的方法,commandProperties 属性指定了异常条件

(2)主启动类加注解 @EnableCircuitBreaker

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class ProvideHystrixApplication {
    
    
    public static void main(String[] args) {
    
    
            SpringApplication.run(ProvideHystrixApplication.class,args);
        }

2、客户端服务降级

注:客户端指的是调用的一方。

(1)在 yml 中配置启动 feign 的 hystrix 支持

feign:
  hystrix:
    #如果处理自身的容错就开启。
    enabled: true

(2)主启动类加上启用注解 @EnableHystrix

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
public class ConsumerFeignHystrixApplication {
    
    
    public static void main(String[] args) {
    
    
 
            SpringApplication.run(ConsumerFeignHystrixApplication.class,args);
        }
}

(3)在 controller 中配置 fallback 降级兜底方法

@RestController
@Slf4j
public class ConsumeFeignHystrixController {
    
    
    @Resource
    private ConsumeFeignHystrixService consumeFeignHystrixService;
 
    @GetMapping(value = "/payment/ok/{id}")
    public String getOK(@PathVariable("id") Integer id) {
    
    
        return consumeFeignHystrixService.getOk(id);
    }
 
    @GetMapping(value = "/payment/timeout/{id}")
    @HystrixCommand(fallbackMethod = "fallbackHystrix_handler_order", commandProperties = {
    
    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
    public String getTimeout(@PathVariable("id") Integer id) {
    
    
        return consumeFeignHystrixService.getTimeout(id);
    }
 
    public String fallbackHystrix_handler_order(@PathVariable("id") Integer id){
    
    
        return "80请求服务失败";
    }
}

此处设置的请求超时时间为1500毫秒,而8001提供的服务超时时间是3000毫秒,所以客户端请求会直接请求超时,调用服务降级fallback方法

3、全局服务降级配置

上面是服务降级举例是在每个业务方法都制定一个兜底的 fallback 方法,这样会造成代码膨胀,而且降级 fallback 方法和业务代码混乱在一起。所以一般对相同的兜底的 fallback 方法进行全局配置处理,从而使全局 fallback 和单独的 fallback 相结合。

1、服务端全局服务降级 DefaultProperties

除了个别重要核心业务有专属,其它普通的可以通过 @DefaultProperties(defaultFallback = “”) 统一跳转到统一处理结果页面,通用的和独享的各自分开,避免了代码膨胀,合理减少了代码量

(1)在 yml 中配置启动 feign 的 hystrix 支持

feign:
 hystrix:
   #如果处理自身的容错就开启。
   enabled: true

(2)主启动类加上启用注解 @EnableHystrix

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
public class ConsumerFeignHystrixApplication {
     
     
   public static void main(String[] args) {
     
     

           SpringApplication.run(ConsumerFeignHystrixApplication.class,args);
       }
}

(3) 在 controller 上加统一 @DefaultProperties(defaultFallback = "globle_fallbackHystrix_handler") 注解;在需要服务降级的方法上加 @HystrixCommand 注解

@RestController
@Slf4j
@DefaultProperties(defaultFallback = "globle_fallbackHystrix_handler")
public class OrderFeignHystrixController {
     
     
   @Resource
   private OrderFeignHystrixService orderFeignHystrixService;

   @GetMapping(value = "/payment/ok/{id}")
   @HystrixCommand
   public String getOK(@PathVariable("id") Integer id) {
     
     
       return orderFeignHystrixService.getOk(id);
   }

   @GetMapping(value = "/payment/timeout/{id}")
   @HystrixCommand(fallbackMethod = "fallbackHystrix_handler_order", commandProperties = {
     
     @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
   public String getTimeout(@PathVariable("id") Integer id) {
     
     
       return orderFeignHystrixService.getTimeout(id);
   }

   public String fallbackHystrix_handler_order(@PathVariable("id") Integer id){
     
     
       return "80请求服务失败";
   }

   public String globle_fallbackHystrix_handler(){
     
     
       return "请求服务失败,返回全局服务降级处理方法";
   }
}

如果有些方法无法使用统一的 fallback 方法,可以在该方法上使用 @HystrixCommand(fallbackMethod =“paymentFallback_handler”, commandProperties = { @HystrixProperty(name=“execution.isolation.thread.timeoutInMilliseconds”,value = “5000”) }) 注解为其单独定制 fallback 方法。

2、客户端通配服务降级 FeignFallback

客户端去调用服务端,碰上服务端宕机或关闭,可以为 Feign 客户端定义的接口添加一个服务降级处理的实现类即可实现解耦

(1)在 yml 中配置启动 feign 的 hystrix 支持

feign:
 hystrix:
   #如果处理自身的容错就开启。
   enabled: true

(2)新建 FallbackServiceHandler 类,实现 feign 接口 OrderFeignHystrixService,并重写每一个方法,作为兜底 fallback 服务降级

@Component
public class FallbackServiceHandler implements OrderFeignHystrixService {
     
     

   public String getOk(Integer id) {
     
     
       return null;
   }

   public String getTimeout(Integer id) {
     
     
       return null;
   }
}

(3)在 OrderFeignHystrixService 的 feign 注解上指定兜底 fallback 服务降级类(该类是 OrderFeignHystrixService 的实现类 FallbackServiceHandler)

@Component 
// 指定 FallbackServiceHandler 类
@FeignClient(value = "CLOUD-PAYMENT-SERVICE-HYSTRIX", fallback = FallbackServiceHandler.class) 
public interface OrderFeignHystrixService {
     
     
 
 
    @GetMapping(value = "/payment/ok/{id}")
    public String getOk(@PathVariable("id") Integer id);
 
    @GetMapping(value = "/payment/timeout/{id}")
    public String getTimeout(@PathVariable("id") Integer id); 
  } 

如果被调用的服务端能正常提供服务,则调用服务端;如果服务端不能正常被调用,则调用 fallback 方法,即 OrderFeignHystrixService 的实现类中对应的方法

四、Hystrix 进行服务熔断

熔断机制概述

熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路(自我恢复)。

在 Spring Cloud 框架里,熔断机制通过 Hystrix 实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是 5 秒内 20 次调用失败,就会启动熔断机制。熔断机制的注解是 @HystrixCommand。

在这里插入图片描述
步骤说明

(1)创建 HystrixCommand(用在依赖的服务返回单个操作结果的时候)或 HystrixObserableCommand(用在依赖的服务返回多个操作结果的时候)对象
(2)命令执行。
(3)其中 HystrixCommand 实现了下面前两种执行方式

1)execute():同步执行,从依赖的服务返回一个单一的结果对象或是在发生错误的时候抛出异常。
2)queue():异步执行,直接返回一个 Future 对象,其中包含了服务执行结束时要返回的单一结果对象。

(4)而 HystrixObservableCommand 实现了后两种执行方式:

1)obseve():返回 Observable 对象,它代表了操作的多个统果,它是一个 Hot Observable (不论“事件源”是否有“订阅者”,都会在创建后对事件进行发布,所以对于 Hot Observable 的每一个“订阅者”都有可能是从“事件源”的中途开始的,并可能只是看到了整个操作的局部过程)。
2) toObservable():同样会返回 Observable 对象,也代表了操作的多个结果,但它返回的是一个Cold Observable(没有“订间者”的时候并不会发布事件,而是进行等待,直到有“订阅者"之后才发布事件,所以对于Cold Observable 的订阅者,它可以保证从一开始看到整个操作的全部过程)。

(5)若当前命令的请求缓存功能是被启用的,并且该命令缓存命中,那么缓存的结果会立即以 Observable 对象的形式返回。
(6)检查断路器是否为打开状态。如果断路器是打开的,那么Hystrix不会执行命令,而是转接到fallback处理逻辑(第8步);如果断路器是关闭的,检查是否有可用资源来执行命令(第5步)。
(7)线程池/请求队列信号量是否占满。如果命令依赖服务的专有线程地和请求队列,或者信号量(不使用线程的时候)已经被占满,那么Hystrix也不会执行命令,而是转接到fallback处理理辑(第8步) 。
(8)Hystrix 会根据我们编写的方法来决定采取什么样的方式去请求依赖服务。

1) HystrixCommand.run():返回一个单一的结果,或者抛出异常。
2)HystrixObservableCommand.construct():返回一个Observable对象来发射多个结果,或通过onError发送错误通知。

(9)Hystix 会将“成功”、“失败”、“拒绝”、“超时” 等信息报告给断路器,而断路器会维护一组计数器来统计这些数据。断路器会使用这些统计数据来决定是否要将断路器打开,来对某个依赖服务的请求进行"熔断/短路"
(10)当命令执行失败的时候,Hystix 会进入 fallback 尝试回退处理,我们通常也称波操作为“服务降级”。而能够引起服务降级处理的情况有下面几种:

1)第4步∶当前命令处于“熔断/短路”状态,断洛器是打开的时候。
2)第5步∶当前命令的钱程池、请求队列或者信号量被占满的时候。
3)第6步∶HystrixObsevableCommand.construct()或HytrixCommand.run()抛出异常的时候。

(11)当 Hystrix 命令执行成功之后,它会将处理结果直接返回或是以 Observable 的形式返回。
tips:如果我们没有为命令实现降级逻辑或者在降级处理逻辑中抛出了异常,Hystrix 依然会运回一个Obsevable 对象,但是它不会发射任结果数惯,而是通过 onError 方法通知命令立即中断请求,并通过onError方法将引起命令失败的异常发送给调用者。

Hystrix 服务端使用

1、客户端配置文件开启 feign 的 hystrix

#开启
feign:
  hystrix:
    enabled: true

2、服务端 servicer 熔断配置

@Service
public class ProvideService{
    
        
    
    //=====服务熔断
    @HystrixCommand(fallbackMethod = "provideCircuitBreaker_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 provideCircuitBreaker(@PathVariable("id") Integer id) {
    
    
        if(id < 0) {
    
    
            throw new RuntimeException("******id 不能负数");
        }
        String serialNumber = IdUtil.simpleUUID();

        return Thread.currentThread().getName()+"\t"+"调用成功,流水号: " + serialNumber;
    }

	// 兜底方法
    public String provideCircuitBreaker_fallback(@PathVariable("id") Integer id) {
    
    
        return "id 不能负数,请稍后再试,/(ㄒoㄒ)/~~   id: " +id;
    }
}

断路器在什么情况下开始起作用:

涉及到断路器的三个重要参数:
1)快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。
2)请求总数阀值:在快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次7,即使所有的请求都超时或其他原因失败,断路器都不会打开。
3)错误百分比阀值:当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阀值情况下,这时候就会将断路器打开。

3、服务端 controller 调用 servicer

@RestController
@Slf4j
public class ProvideController
{
    
    
    @Resource
    private ProvideService provideService;

    ...
    
    //====服务熔断
    @GetMapping("/provide/circuit/{id}")
    public String provideCircuitBreaker(@PathVariable("id") Integer id)
    {
    
    
        String result = provideService.provideBreaker(id);
        log.info("****result: "+result);
        return result;
    }
}

4、测试

正确输入: http://localhost:8001/provide/circuit/1

错误输入:http://localhost:8001/provide/circuit/-1

多次错误,再来次正确,但错误得显示

重点测试 - 多次错误,然后慢慢正确,发现刚开始不满足条件,就算是正确的访问地址也不能进行

总结

(1)断路器开启或者关闭的条件

1)到达以下阀值,断路器将会开启:

当满足一定的阀值的时候(默认10秒内超过20个请求次数)
当失败率达到一定的时候(默认10秒内超过50%的请求失败)

2)当开启的时候,所有请求都不会进行转发

3)一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。

(2)断路器打开之后

再有请求调用的时候,将不会调用主逻辑,而是直接调用降级fallback。通过断路器,实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟的效果。

(3)原来的主逻辑要如何恢复呢?

hystrix 为我们实现了自动恢复功能。

当断路器打开,对主逻辑进行熔断之后,hystrix 会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,当休眠时间窗到期,断路器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时

(4)HystrixCommandProperties 的配置

@HystrixCommand(fallbackMethod = "fallbackMethod", 
                groupKey = "strGroupCommand", 
                commandKey = "strCommand", 
                threadPoolKey = "strThreadPool",
                
                commandProperties = {
    
    
                    // 设置隔离策略,THREAD 表示线程池 SEMAPHORE:信号池隔离
                    @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
                    // 当隔离策略选择信号池隔离的时候,用来设置信号池的大小(最大并发数)
                    @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10"),
                    // 配置命令执行的超时时间
                    @HystrixProperty(name = "execution.isolation.thread.timeoutinMilliseconds", value = "10"),
                    // 是否启用超时时间
                    @HystrixProperty(name = "execution.timeout.enabled", value = "true"),
                    // 执行超时的时候是否中断
                    @HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "true"),
                    
                    // 执行被取消的时候是否中断
                    @HystrixProperty(name = "execution.isolation.thread.interruptOnCancel", value = "true"),
                    // 允许回调方法执行的最大并发数
                    @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "10"),
                    // 服务降级是否启用,是否执行回调函数
                    @HystrixProperty(name = "fallback.enabled", value = "true"),
                    // 是否启用断路器
                    @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
                    // 该属性用来设置在滚动时间窗中,断路器熔断的最小请求数。例如,默认该值为 20 的时候,如果滚动时间窗(默认10秒)内仅收到了19个请求, 即使这19个请求都失败了,断路器也不会打开。
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
                    
                    // 该属性用来设置在滚动时间窗中,表示在滚动时间窗中,在请求数量超过 circuitBreaker.requestVolumeThreshold 的情况下,如果错误请求数的百分比超过50, 就把断路器设置为 "打开" 状态,否则就设置为 "关闭" 状态。
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
                    // 该属性用来设置当断路器打开之后的休眠时间窗。 休眠时间窗结束之后,会将断路器置为 "半开" 状态,尝试熔断的请求命令,如果依然失败就将断路器继续设置为 "打开" 状态,如果成功就设置为 "关闭" 状态。
                    @HystrixProperty(name = "circuitBreaker.sleepWindowinMilliseconds", value = "5000"),
                    // 断路器强制打开
                    @HystrixProperty(name = "circuitBreaker.forceOpen", value = "false"),
                    // 断路器强制关闭
                    @HystrixProperty(name = "circuitBreaker.forceClosed", value = "false"),
                    // 滚动时间窗设置,该时间用于断路器判断健康度时需要收集信息的持续时间
                    @HystrixProperty(name = "metrics.rollingStats.timeinMilliseconds", value = "10000"),
                    
                    // 该属性用来设置滚动时间窗统计指标信息时划分"桶"的数量,断路器在收集指标信息的时候会根据设置的时间窗长度拆分成多个 "桶" 来累计各度量值,每个"桶"记录了一段时间内的采集指标。
                    // 比如 10 秒内拆分成 10 个"桶"收集这样,所以 timeinMilliseconds 必须能被 numBuckets 整除。否则会抛异常
                    @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10"),
                    // 该属性用来设置对命令执行的延迟是否使用百分位数来跟踪和计算。如果设置为 false, 那么所有的概要统计都将返回 -1。
                    @HystrixProperty(name = "metrics.rollingPercentile.enabled", value = "false"),
                    // 该属性用来设置百分位统计的滚动窗口的持续时间,单位为毫秒。
                    @HystrixProperty(name = "metrics.rollingPercentile.timeInMilliseconds", value = "60000"),
                    // 该属性用来设置百分位统计滚动窗口中使用 “ 桶 ”的数量。
                    @HystrixProperty(name = "metrics.rollingPercentile.numBuckets", value = "60000"),
                    // 该属性用来设置在执行过程中每个 “桶” 中保留的最大执行次数。如果在滚动时间窗内发生超过该设定值的执行次数,
                    // 就从最初的位置开始重写。例如,将该值设置为100, 滚动窗口为10秒,若在10秒内一个 “桶 ”中发生了500次执行,
                    // 那么该 “桶” 中只保留 最后的100次执行的统计。另外,增加该值的大小将会增加内存量的消耗,并增加排序百分位数所需的计算时间。
                    @HystrixProperty(name = "metrics.rollingPercentile.bucketSize", value = "100"),
                    
                    // 该属性用来设置采集影响断路器状态的健康快照(请求的成功、 错误百分比)的间隔等待时间。
                    @HystrixProperty(name = "metrics.healthSnapshot.intervalinMilliseconds", value = "500"),
                    // 是否开启请求缓存
                    @HystrixProperty(name = "requestCache.enabled", value = "true"),
                    // HystrixCommand的执行和事件是否打印日志到 HystrixRequestLog 中
                    @HystrixProperty(name = "requestLog.enabled", value = "true"),

                },
                threadPoolProperties = {
    
    
                    // 该参数用来设置执行命令线程池的核心线程数,该值也就是命令执行的最大并发量
                    @HystrixProperty(name = "coreSize", value = "10"),
                    // 该参数用来设置线程池的最大队列大小。当设置为 -1 时,线程池将使用 SynchronousQueue 实现的队列,否则将使用 LinkedBlockingQueue 实现的队列。
                    @HystrixProperty(name = "maxQueueSize", value = "-1"),
                    // 该参数用来为队列设置拒绝阈值。 通过该参数, 即使队列没有达到最大值也能拒绝请求。
                    // 该参数主要是对 LinkedBlockingQueue 队列的补充,因为 LinkedBlockingQueue 队列不能动态修改它的对象大小,而通过该属性就可以调整拒绝请求的队列大小了。
                    @HystrixProperty(name = "queueSizeRejectionThreshold", value = "5"),
                }
               )
public String doSomething() {
    
    
	...
}

猜你喜欢

转载自blog.csdn.net/IT__learning/article/details/121712616