Hystrix 限流、超时、熔断和降级

       在高并发访问下,系统所依赖的服务的稳定性对系统的影响非常大,依赖有很多不可控的因素,比如网络连接变慢,资源突然繁忙,暂时不可用,服务脱机等。我们要构建稳定、可靠的分布式系统,就必须要有这样一套容错方法。

      Hystrix是Netflix开源的一款容错框架,包含常用的容错方法:线程隔离、信号量隔离、降级策略、熔断技术。

一、限流

      在高并发访问下,由于系统资源有限,必须对访问量进行控制。Hystrix提供了限流功能,在springcloud架构的系统中,可以在网关启用Hystrix,进行限流处理,每个微服务也可以各自启用Hystrix进行限流。

      Hystrix默认使用线程隔离模式,可以通过线程数+队列大小进行限流,通过以下参数进行控制:

1.hystrix.threadpool.default.coreSize
线程池核心线程大小,熟悉java线程池的都了解,线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会被销毁,这里的最小线程数量即是corePoolSize。

2.hystrix.threadpool.default.maximumSize
线程池最大线程数量,这也是java线程池的基本概念,一个任务被提交到线程池以后,首先会找有没有空闲存活线程,如果有则直接将任务交给这个空闲线程来执行,如果没有则会缓存到工作队列中,如果工作队列满了,才会创建一个新线程,然后从工作队列的头部取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列尾部。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。

3.hystrix.threadpool.default.maxQueueSize
该参数指定工作队列的最大值,前面提到一个任务被提交到线程池以后,如果没有空闲线程来执行则会缓存到工作队列中,maxQueueSize参数就是指定工作队列的最大值,默认是-1。
如果是-1的话,创建的是SynchronousQueue,大于0则根据其大小创建LinkedBlockingQueue。
SynchronousQueue是不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。也就是说,如果是-1的话,hystrix不使用队列。

4.hystrix.threadpool.default.queueSizeRejectionThreshold
这个属性是控制队列最大阈值的,而Hystrix默认只配置了5个,因此就算我们把maxQueueSize的值设置再大,也是不起作用的。两个属性必须同时配置。设计这个参数的原因在于BlockingQueue的大小不能动弹调整,因此使用这个参数来满足动弹调整的需求。

hystrix:
  threadpool:
    default:
      coreSize: 200 #并发执行的最大线程数,默认10
      maxQueueSize: 1000 #BlockingQueue的最大队列数,默认值-1
      queueSizeRejectionThreshold: 800 #即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝,默认值5

二、超时

      加入超时机制,通过设置超时时间,超过这个时间就会直接返回了,那么这样就在一定程度上可以抑制消费者资源耗尽的问题

1.hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
降级处理超时时间设置,默认情况下调用接口能够触发Hystrix服务降级处理的超时时间是1000ms,也就是才1秒钟,一般会调大。
 

三、熔断

       当依赖的服务有大量超时时,在让新的请求去访问根本没有意义,只会无畏的消耗现有资源,如果短时间内有大量请求在超时时间内都得不到响应,就意味着这个服务出现了异常,此时就没有必要再让新的请求去访问这个服务了,这个时候就应该使用熔断器进行熔断处理避免资源浪费。
       熔断器3种状态:关闭、打开、半开。正常状态下,熔断器处于关闭状态(Closed),如果调用持续出错或者超时,熔断器被打开进入熔断状态(Open),后续一段时间内的所有调用都会被拒绝(Fail Fast),这个拒绝时间默认是5s。“一段时间“以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试,如果调用仍然失败,则回到熔断状态,如果调用成功,则回到断路闭合状态。

1.hystrix.command.default.metrics.rollingStats.timeInMilliseconds
设置统计的时间窗口值的毫秒值,circuit break 的打开会根据1个rolling window的统计来计算。若rolling window被设为10000毫秒,则rolling window会被分成n个buckets,每个bucket包含success,failure,timeout,rejection的次数的统计信息。默认10000。

该属性主要用来设置熔断监控的时间区间,整个熔断过程将实时统计每个时间区间内的监控数据。并计算该时间区间内的错误率(errorPercentage),如果错误率达到用户设置的阈值,则断路器将进行熔断处理,以此实现断路器熔断功能。在这里大家有时很容易产生一个疑问,这个时间区间时连续的吗?回答是:不是连续的,整个hystrix对于时间区间控制为rolling(旋转的),如下图所示:

 

当系统时钟通过一个Time时,就会判断n == numBuckets是否相等,如果相等,则第一个Bucket将被舍弃,同时创建一个新的Bucket,将这个Time时间内的所有维度在该Bucket内进行计数统计。

2.hystrix.command.default.metrics.rollingStats.numBuckets
设置一个rolling window被划分的数量,若numBuckets=10,rolling window=10000,那么一个bucket的时间即1秒。必须符合rolling window % numberBuckets == 0,否则会抛出异常。默认10

当执行到下一个时间区间时,创建新的bucket,并将该时间区间的数据记录到对应的指标上。当Bucket数量==用户设置的Buckets数量时,将第一个Bucket进行舍弃操作,并创建新的Bucket。即任何一个时间点断路器内部最多存在BucketsNum个Bucket。

在高并发的环境里,每个桶的时间长度建议大于100ms

3.hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds
采样间隔,即记录health快照(用来统计成功和错误率)的间隔,默认500ms

4.hystrix.command.default.circuitBreaker.requestVolumeThreshold
熔断器在整个统计时间内是否开启的阀值,默认20。也就是当一个rolling window的时间内至少请求20次,熔断器才发挥起作用。如果收到19个请求,即使19个请求都失败,也不会触发circuit break。

5.hystrix.command.default.circuitBreaker.errorThresholdPercentage
错误比率阀值,如果错误率>=该值,circuit会被打开,并短路所有请求触发fallback。默认50

6.hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds
熔断器工作时间毫秒值,默认:5000。则当触发circuit break后的5000毫秒内都会拒绝request,也就是5000毫秒后才会关闭circuit。5秒后会关闭circuit重试(半熔断状态),如果请求仍然失败,继续打开熔断器5秒,如此循环。

四、降级

所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的fallback(回退)回调,返回一个缺省值。 例如:(备用接口/缓存/mock数据),这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。

除了熔断外,超时和限流的情况下,也会走降级处理程序。如果没有提供fallback降级处理程序,则直接抛出异常,如果fallback程序自己发生错误也抛出异常。

1.hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests
这个属性主要是来控制Hystrix超时和降级并行的线程数,也就是调用线程允许请求HystrixCommand.GetFallback()的最大数量,默认10。如果需要降级的线程并行数超过这个属性所设置的值,则会直接报HystrixRuntimeException的异常。
Hystrix对于普通RuntimeException异常报错请求都会进行fallback降级处理,但是对于HystrixRuntimeException不会降级,这个异常是Hystrix自己抛出来的,用来提示请求方请求失败。
不要通过这个配置的名字来看,以为只是针对于Semaphore模式下的Hystrix的降级处理,该项配置对于THREAD隔离模式也起作用。

五、总结

一次远程服务调用过程如下:

1.判断熔断器(circuit-breaker)是否打开或者半打开状态,如果打开跳到步骤6,进行回退策略,如果关闭进入步骤2。

2.判断线程池/队列/信号量(使用了舱壁隔离模式)是否跑满,如果跑满进入回退步骤6,否则继续后续步骤3。

3.执行实际的服务调用。

    a. 服务调用发生超时时,进入步骤6。

4.判断调用方法中的代码是否执行成功。

    a. 执行成功返回结果。

    b. 执行中出现错误则进入步骤6。

5.所有的运行状态(成功,失败,拒绝,超时)上报给熔断器,用于统计从而影响熔断器状态。

6.进入getFallback()回退逻辑。

    a. 没有实现getFallback()回退逻辑的调用将直接抛出异常。

    b. 回退逻辑调用成功直接返回。

    c. 回退逻辑调用失败抛出异常。

7.返回执行成功结果。

  • 3
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值