暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Hystrix 熔断和降级

阿哲是哲学的哲 2021-02-05
4795

一. 服务熔断的原因

1. 雪崩效应

    长链路调用过程中, A->B->C.... 假设链路上 C 出现了调用缓慢->B也会延迟->A也会延迟,堵住的 A 请求会消耗占用系统的线程、IO 等资源. 当对 A 服务的请求越来越多,占用的计算机资源越来越多的时候,会导致系统瓶颈出现,造成其他的请求同样不可用,最终导致业务系统崩溃,这种现象称为雪崩效应。

2. 熔断机制 - 用于解决雪崩效应的问题

    当请求失败(超时或者其他异常)次数超过预设值时,熔断器自动打开. 

    这时所有经过这个熔断器的请求都会直接返回失败(不会堵住A请求),并没有真正到达所依赖的服务上。

二. SpringCloud 使用 Hystrix 来实现服务熔断与降级

1. 实现原理

    Hystrix 是一种开关装置,类似于熔断保险丝。在消费者端安装一个 Hystrix 熔断器,当 Hystrix 监控到某个服务发生故障后熔断器会开启,将此服务访问链路断开。 

      不过 Hystrix 并不会将该服务的消费者阻塞,或向消费者抛出异常,而是向消费者返回一个符合预期的备选响应(FallBack)。 通过 Hystrix 的熔断与降级功能,避免了服务雪崩的发生,同时也考虑到了用户体验。故 Hystrix 是系统的一种防御机制。

2.实现方式:  fallbackMethod服务降级 和 fallbackFactory服务降级

fallbackMethod服务降级:

    指定该方法要使用服务降级。即当前处理器方法在运行过程中若发生异常,无法给客户端正常响应时,就会调用fallbackMethod指定的方法

// fallbackMethod 指定回调的方法
// HystrixProperty 添加专属于本方法的回调参数
// execution.isolation.thread.timeoutInMilliseconds = 2000 本方法的熔断时长为2s
@HystrixCommand(fallbackMethod = "getHystrixHandler",
            commandProperties = @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="2000"))
    @GetMapping("/get/{id}")
    public Depart getByIdHandler(@PathVariable("id") int id) {
        return fegin.getDepartById(id);
    }

    // 定义服务降级方法,即响应给客户端的备选方案
    public Depart getHystrixHandler(@PathVariable("id") int id) {
        return new Depart(id," ");
    }

fallbackFactory服务降级

1. 实现FallbackFactory 泛型工厂

// 定义 FallbackFactory<T> 的实现类 , 实现 T create(Throwable var1) 方法, 在方法体内实现fallback方法
@Component
public class DepartFallbackFactory implements FallbackFactory<XxxService{
     @Override
    public XxxService create(Throwable throwable) {
        return new XxxService() {......}
    }
}

// 在Fegin接口中指定 fallbackFactory用于指定当前Feign接口的服务降级类
@FeignClient(value = "提供者服务名", fallbackFactory = XxxFallbackFactory.class)

2. 面向接口实现本地失败回调

//面向接口实现失败回调
@Component
public class XxxFallback implements XxxService {
    ...
}
//接口上指定使用XxxFallback实现类作为失败回调的
@FeignClient(value = "提供者服务名", fallback = XxxFallback.class)
public interface XxxService 
{
    ....
}

3. fallbackMethod降级 和 fallbackFactory降级 的优先级

  1. 取timeoutInMilliseconds 的最小值生效: 
    方法级别用@HystrixProperty 独立标记熔断时间和全局配置中hystrix.command.default 的全局通用熔断时间

  2. fallbackFactory 级别比 fallbackMethod 高

4. Hystrix 组件的独立性

    Hystrix 在并非专用于Fegin 调用的返回失败场景中, 在普通的方法中使用依旧可以生效

@HystrixCommand(fallbackMethod = "getHystrixHandler")
@GetMapping("/get/{id}")
public Depart getByIdHandler(@PathVariable("id") int id) {
    return service.get(id);
}

// 定义服务降级方法,即响应给客户端的备选方案
public Depart getHystrixHandler(@PathVariable("id") int id) {
    return new Depart(id," ");
}

三. 执行隔离策略

1. 何为执行隔离?

    对依赖的请求数量进行限制的这种机制,称为执行隔离。

    执行隔离策略有两大作用:防止服务熔断,防止服务雪崩

2. 隔离的类型

  • 线程隔离 thread (默认):系统会创建一个依赖线程池,为每个依赖请求分配一个独立的线程,而每个依赖所拥有的线程数量是有上限的。当对该依赖的调用 请求数量达到上限后再有请求,则该请求阻塞。所以对某依赖的并发量取决于为该依赖 所分配的线程数量。

    适用于: 耗时长, 高吞吐量, 例如读数据库, 大计算.

  • 信号量隔离:对依赖的调用所使用的线程仍为请求线程,即不会为依赖请求再新创建新的线程。但系统会为每种依赖分配一定数量的信号量,而每个依赖请求分配一个信号号。当对该依赖的调用请求数量达到上限后再有请求,则该请求阻塞。所以对某依赖的并发 量取决于为该依赖所分配的信号数量。

    适用于:耗时短, 低延迟, 例如高频读取缓存


线程隔离信号量隔离
线程请求线程和调用线程是两个分开的线程请求线程和调用线程是同一个线程
开销排队等待可用线程, 调用上线文CPU切换线程无序切换线程
异步支持不支持
并发支持支持(线程池限制)支持(设定的信号量限制)
传递header无法传递 Http Header可传递 Http Header
支持超时可支持超时不支持超时

3. 设置

hystrix.command.default.execution.isolation.strategy=thread hystrix.command.default.execution.isolation.strategy=semaphore

执行隔离其它属性

# 若采用线程执行隔离策略, 开启线程的执行时间超时
hystrix.command.default.execution.timeout.enabled = (true) 
# 若采用线程执行隔离策略, 执行线程超时时限长度
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds = (1000ms) 
# 当线程执行超时时是否中断线程的执行
hystrix.command.default.execution.isolation.thread.interruptOnTimeout = (true) 
# 请求取消,当前执行线程是否结束
hystrix.command.default.execution.isolation.thread.interruptOnCancel = (false) 
# 若采用信号量执行隔离策略,则可通过以下属性修改信号量的数量
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests =    

熔断器属性

# 当前应用是否开启熔断器功能
hystrix.command.default.circuitBreaker.enabled = (true)
# 在窗口期内(一个时间段内) 收到的请求数量超过该设置的数量后,将开启熔断器
hystrix.command.default.circuitBreaker.requestVolumeThreshold = (20) 
# 窗口期时间
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds = (5000ms) 
# 当请求的错误率高于该百分比时,开启熔断器。
hystrix.command.default.circuitBreaker.errorThresholdPercentage = (50 即为50%) 
# 强制开启熔断器, 熔断所有请求
hystrix.command.default.circuitBreaker.forceOpen = (false) 
# 强制关闭所有熔断器, 通过所有请求
hystrix.command.default.circuitBreaker.forceClosed = (false)

四. 熔断时间设置

    对于最终触发熔断超时时长的原因 , 除了 hystrix 的 timeoutInMilliseconds 自生有关 如果 ribbon 的 ReadTimeout 超时也会抛出读超时, 此时也会触发熔断. 如果有Zuul 设置超时时长原理类似

feign:
  client:
    config:
      default:
        connectTimeout: 6000 # 指定Feign客户端连接提供者的超时时限
        readTimeout: 6000 # 指定Feign客户端连接上提供者后,向提供者进行提交请求,从提交时刻开始,到接收到响应,这个时段的超时时限

ribbon:
  ReadTimeout: 5000   #负载均衡超时时间,默认值5000
  ConnectTimeout: 2000 #ribbon请求连接的超时时间,默认值2000

hystrix:
  command: # 全局配置
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 4000 # 断路器超时时间,默认1000ms
  XxxApi#apiMethod(String,Integer,Boolean):  # 特定接口配置局配置 (括号内填写参数类型)
    execution:    
      timeout:
        enabled: true # 开启线程的执行时间超时
          isolation:
            thread:
              timeoutInMilliseconds: 6000  # 断路器超时时间,默认1000ms      

  1. ribbon 中的 connectTimeout连接时长 和 ReadTimeout读取时长, ribbon: 会被  feign:client 配置覆盖掉

  2. hystrix 中的 timeoutInMilliseconds熔断时间 优先级: 特定接口>全局通用, 特定配置可以在 yml或者通过@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="4000") 进行配置

  3. 假设此接口开启了hystrix熔断器的前提下, ReadTimeout 和 timeoutInMilliseconds 取时间短的进行读超时, 读超时会触发熔断

  4. 开启熔断器的条件

    • 启动标签包含 @SpringCloudApplication 或者 @EnableCircuitBreaker 支持熔断器
    • feign:hystrix:enabled: true(默认false不开启 ) OpenFeign全局接口开启熔断器, 使得fegin中的fallback标签生效
    • hystrix:command:default:execution:timeout:enabled: true 使得@HystrixCommand(fallbackMethod = "回退方法")生效
  5. ribbon还有MaxAutoRetries对当前实例的重试次数,MaxAutoRetriesNextServer对切换实例的重试次数, 如果ribbon的ReadTimeout超时,或者ConnectTimeout连接超时,会进行重试操作

    通常 timeoutInMilliseconds 需要配置的比ReadTimeout长,ReadTimeout比ConnectTimeout长,否则还未重试,就熔断了

    为了确保重试机制的正常运作,理论上(以实际情况为准)建议hystrix的超时时间为:(1 + MaxAutoRetries + MaxAutoRetriesNextServer) * ReadTimeout


文章转载自阿哲是哲学的哲,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论