本文概览:Hystrix实现了服务弹性的三种模式。

  • 在接口超时/失败达到一定阈值,触发断路器Hysgtrix的熔断策略,此时断路器会处于断路状态立刻返回失败,或者若配置了备份策略,会使用执行备份策略来代替返回失败。
  • Hystrix是通过线程池管理服务调用,所以还的介绍了隔离线程池(舱壁模式)和如何支持上下文传递。

1 Hysrix介绍

1.1 服务弹性

服务弹性,主要功能就是指在下游服务出现错误或者超时问题时,通过让客户端快速失败,达到不消耗当前服务的数据库连接和线程池之类资源,从而保护当前服务不被下游服务拖垮。目前常用的策略有:

  • 客户端均衡模式。通过NetflixRibbon来实现
  • 断路器模式。不再调用下游服务,直接返回错误
  • 后备模式。不再调用下游服务,调用备用策略
  • 舱壁模式。通过线程池来访问下游服务,每一个下游服务对应一个线程池。

1.2 Hystrix引入

Hystrix是一种服务弹性的实现,它实现了上面的断路器模式、后备模式、舱壁模式。

Hystrix并不具有限流的功能Hystrix关注的是容错处理,在接口错误或者超时时触发断路器熔断,快速返回错误,还可以支持备份来代替返回失败;在熔断发生后,还支持检查服务是否恢复从而使断路器恢复通路状态。

Hytrix是通过线程池管理调用外部资源的,可以把一个线程池当做一个外部服务。

2 HystrixSpingCloud整合

2.1 maven配置

1、配置

2、启动类添加@EnableCircuitBreaker,表示spring boot中使用hytrix

2.2 断路器的流程和三种模式

如下图,对应三个阶段

  • 第一阶段: 正常
  • 第二阶段: 发现超时或者失败时,标识失败
  • 第三阶段:达到阈值之后。标识服务不可以用,熔断器启动断开,此时如果BC的访问,短路器会给B立刻返回失败,不会再调用C。同时会进行间断尝试,判断服务是否恢复。

767387

Hystricx存在三种模式,舱壁模式和后备模式两种模式都需要在断路器模式上进行的完善。

  • 断路器模式,设置超时或者失败等熔断策略。
  • 后备策略模式:在第二阶段或者第三阶段失败时,如果存在后备策略,都会执行后备策略。
  • 舱壁模式,保证一个服务独享一个线程池。

综上,Hystrix断路器的功能如下:

1)熔断触发前,超时或者失败发生时:

  • 存在后备策略,执行后备策略
  • 不存后备策略,抛异常处理

2)在熔断触发之后,可以立刻返回失败,保护下游失败。

  • 存在后备策略,执行后备策略
  • 不存后备策略,抛异常处理

3)在熔断器触发之后,还能定期检查服务是否正常,将服务恢复正常。

2.2 断路器模式

通过@HystrixCommand设置超时未1s,此时超过1s之后,请求就会返回抛异常处理

在如下Controller中进行测试

返回结果

这里有个问题就是:

这里实现操作就是超过1s之后,就抛异常处理,这种方式并没有减少对下游服务的调用,还是会不断的调用下游服务,而不是彻底断开,直接由Hystricx返回错误。并没有体现出“快速失败”?

可以参考上面的断路器的图,此时错误属于第二阶段错误,还没有触发断路器模式,只有达到断路器触发短路条件之后,进入第三个阶段,此时断路器会立刻断开第三方服务,请求不会发到第三方了,断路器直接返回错误,即“快速失败”。

2.3 后备模式

使用后备模式要点

  • 需要在@HystrixCommand注解中添加一个名为fallbackMethod的属性
  • 后备方法必须跟使用了@HysrixCommand原始方法在同一个类中。
  • 后备方法必须是public类型
  • 后备方法参数必须和原方法一致

2.3.1 调用失败场景下的后备策略

调用使用了@HystrixCommand的controller代码如下

具有后备模式 的函数如下

结果为

42138574

2.3.2 调用超时情况下后备策略

Controller的代码如下:

耗时备用策略为:

执行结果为,在超过2s之后,就调用了后备策略。

51963139

2.4 舱壁模式

Hytrix是通过线程池管理调用外部资源的,默认情况下所有服务调用都公用一个线程池,如下图

810744

 

舱壁模式功能就是:我们可以通过为各个服务分别指定线程池,如下图

835296

代码如下,通过threadPoolKeythreadPoolProperties来指定:

2.5 常见错误:

1、method wasn’t found

解决方法,需要查看后备函数:

  • 返回类型需要是public类型
  • 参数必须和原方法一致。
  • 定义的后备函数名字和fallbackMethond属性中配置的要一样,包括大小写都要一致。

3  配置短路器触发策略

执行策略流程图如下:

Hystrix遇到一个超时/失败请求,此时启动一个10s的窗口,后续的请求会进行如下判断:

(1)查看失败次数是否超过最小调用次数

  • 如果没有超过,则放行请求。
  • 如果超过最小请求数,继续下面逻辑

(2)判断失败率是否超过一个阈值,这里错误是指超时和失败两种。

  • 如果没有超过,则放行
  • 如果超过错误阈值,则继续下面逻辑

(3)熔断器断开

  • 请求会直接返回失败。
  • 会开一个5s的窗口,每隔5s调用一次请求,如果成功,表示下游服务恢复,否则继续保持断路器断开状态。

3598211

涉及到属性有五个:

  • circuitBreaker.requestVolumeThreshold,在统计时间窗口中,请求最小次数
  • circuitBreaker.errorThresholdPercentage,熔断断开后,间隔7s,就尝试访问一次服务,查看服务是否已经恢复
  • circuitBreaker.sleepWindowInMilliseconds,熔断断开后,间隔7s,就尝试访问一次服务,查看服务是否已经恢复
  • metrics.rollingStats.timeInMilliseconds,在 时间窗口,从监听到第一次失败开始计时。
  • metrics.rollingStats.numBuckets,在时间窗口中,收集统计信息的次数。在15s的窗口中每隔3s就收集一次,共5次。

举例如下:在10s内,请求次数超过4次,失败占比超过50%时,就触发熔断,熔断之后会每隔7s进行重试服务,如果服务恢复,则恢复断路器,否则保持断路状态。

4 Hystrix上下文传递

Hytrix是通过线程池管理调用外部资源的,一个外部服务可以对应一个独立线程池。对于线程池存在传递ThreadLocal的问题。

4.1 ThreadLocal与线程池

在线程池中没有办法获取主线程的threadLocal的信息,如下代码

执行结果为:

为了获取线程池的信息,可以定义如下一个Runnable类,在每一次线程执行时,重新初始化上下文。如下

上面使用线程池的函数修改为使用这个新建的TransmitRunnable,如下

执行结果如下,已经获取到logID了

4.2 Hystrix支持上下文传递

4.2.1 问题复现

在Controller中初始化上下文

在使用Hystrix的函数中使用上下文,发现无法获取上下文

打印日志发现,logId没有获取到

4.2.2 问题解决

需要三个步骤:

  • 定义一个Hystrix并发策略类
  • 定义一个Callable类
  • 配置spring cloud以使用自定义的Hystrix并发策略类

1、自定义Hystrix并发策略类

2、定义一个新的callable

3、配置新的并发策略类

4、执行结果,发现已经可以获取到logId了

附1  @HystrixCommand属性

属性名称

属性功能

子属性

描述

fallbackMethod

后备方法

值为后备方法名字

threadPoolKey

指定线程池

线程池名字

threadPoolProperties

设置线程池属性

core

queueSize

阻塞队列大小

commandProperty

超时

execution.isolation.thread.

timeoutInMilliseconds

耗时时间

断路器熔断策略

circuitBreaker.requestVolumeThreshold

circuitBreaker.errorThresholdPercentage

circuitBreaker.sleepWindowInMilliseconds

metrics.rollingStats.timeInMilliseconds

metrics.rollingStats.numBuckets

附2 需要注解点

1、在使用不带属性的@HystrixCommand注解时,会默认把所有请求第三方服务放置在同一个线程池下面,这样可能导致系统性能问题

附3 相关概念

1、服务降级

服务是集群的,服务降级降级体现就是个别服务不可用。

2、服务重启之后,服务的hytrix信息是否还可以保存?

在服务重启前通过hytrix对下游一个服务进行了后备模式处理,此时服务重启,那么重启之后,对下游服务是否还会进行后备莫模式处理?

参考资料

官网介绍:https://github.com/Netflix/Hystrix/wiki

官网 how it works :https://github.com/Netflix/Hystrix/wiki/How-it-Works

官网 how to use :https://github.com/Netflix/Hystrix/wiki/How-To-Use

 

 

分类&标签