Hystrix,空耳"嗨嘶杰(卷舌)克嘶".由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性、容错性与局部应用的弹性,是一个实现了超时机制和断路器模式的工具类库.
Hystrix主要通过以下几点实现延迟和容错:
包裹请求:使用HystrixCommand包裹对依赖的调用逻辑,每个命令在独立的线程中执行,使用了设计模式中的“命令模式”.
回退机制:当请求失败、超时、被拒绝或者当断路器打开时,执行回退方法.回退方法可由开发者设计.
跳闸机制:当某服务的错误率超过一定阈值,Hystrix可以自动或手动跳闸,停止请求该服务一段时间.
资源隔离:Hystrix为每个依赖都维护一个小型线程池,如果该线程池已满,发往该依赖的请求被立即拒绝,而不是排队等候.
自我修复:断路器打开一段时间后,会自动进入"半开"状态.此时断路器可允许一个请求访问依赖的服务,若请求成功,则断路器关闭;否则断路器继续保持“打开”状态.
监控机制:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等.
在SpringCloud中使用Hystrix仅需以下步骤实现:
1.引入Hystrix的Maven依赖
2.启动类声明@EnableHystrix注解,为项目启动断路器支持
3.在制定方法上声明@HystrixCommand注解,设置回退方法即可
使用消费者服务整合Hystrix,实现服务降级机制
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
启动类声明@EnableHystrix注解
为指定方法声明@HystrixCommand注解,使其具备容错能力.并且指定一个回退方法,使其具备服务降级能力.
这时,仅启动eureka和consumer服务.不启动provider项目,使consumer获取不到provider的实例.
此时,在浏览器输入http://localhost:8181/user/2.查看是否执行回退方法.
由上图测试结果可知,restTemplate对象将找不到springcloud-provider的实例,
满足Hystrix回退机制的请求失败条件,继而执行回退方法(执行回退方法亦可称为服务降级).
服务降级
服务降级是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性。
注意:虽然当请求失败、超时、被拒绝时,请求都会执行回退方法.但并不意味着断路器已经被打开.
为了验证这点,可以引入Spring Boot Actuator服务监控依赖,通过观察/actuator/health端点就可以得知断路器状态了.
使用Actuator监控Hystrix的状态
引入Actuator依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
由于Springboot 2.0以上,/actuator/heath端点不显示所有细节.所以需要简单的配置一下/health端点内容范围.
配置application.yml
management:
endpoint:
#允许/actuator/health端点显示所有细节
health:
show-details: always #包含选项never(默认), always, when-authenticated
此时,Actuator完成整合.重启consumer服务.然后在浏览器输入http://localhost:8181/actuator/health
服务端返回的是一串Json字符串,由上图可以看出hystrix的状态是UP,就是一切正常,此时断路器是关闭的.
跳闸机制
在浏览器输入http://localhost:8181/user/2,让consumer服务执行一次回退方法.
回退方法正常执行,浏览器再次输入http://localhost:8181/actuator/health,查看此时的hystrix的状态.
由上图结果可知,尽管Hystrix执行了回退方法,其状态仍然是UP正常的状态.说明断路器并没有开启.
注意:Hystrix跳闸机制说明是当某服务的错误率超过一定阈值(默认是5秒内20次失败),断路器才会开启,此服务自动"跳闸".
为了验证Hystrix的跳闸机制,那么我在5秒内多次请求http://localhost:8181/user/2地址,使其执行多次回退方法即可验证结果.
持续快速的访问http://localhost:8181/user/2地址后,再次输入http://localhost:8181/actuator/health,查看此时的hystrix的状态.
可以看到,此时hystrix状态为CIRCUIT_OPEN,即断路器已经打开了(全开状态:不再请求指定服务).
details节点表示当前服务UserController控制器的getUserById方法断开一段时间对指定服务的请求("跳闸").
自我修复机制
隔一段时间之后,断路器会由全开状态转变为半开状态,允许一个请求访问指定服务,
如果请求成功,则断路器状态将会转变为关闭状态;否则,将继续转变为全开状态.这是Hystrix的自我修复机制.
为了验证Hystrix的自我修复机制,那么我将开启consumer所请求的provider服务.使其能够成功获取provider实例以进行访问.
启动provider服务
此时浏览器输入http://localhost:8181/user/2地址,便可以正常请求,获取用户信息.
再次输入http://localhost:8181/actuator/health,查看此时的hystrix的状态.
可以看出,断路器已变为UP状态,即断路器已经关闭了.
Hystrix的隔离策略
Hystrix存在资源隔离机制, 为每一个依赖(被@HystrixCommand声明的方法)都维护一个小型线程池.当有请求进入该依赖,则为请求开启一个线程进行处理.当线程池满了,发往该依赖的请求被立即拒绝,而不是进入该依赖等待资源.
Hystrix的隔离策略有两种,分别为线程隔离(Hystrix默认使用)和信号量隔离.
THREAD(线程隔离):使用该方式,HystrixCommand将会在单独的线程上执行,并发请求受线程池中的线程数量限制.
SEMAPHORE(信号量隔离):使用该方式,HystrixCommand将会在调用线程上执行,开销相对较小,并发请求受信号量个数限制. (一般使用于负载非常高、非网络调用和需要传播线程上下文的情况)
Hystrix可使用注解@HystrixProperty(name="execution.isolation.strategy",value="SEMAPHORE")来指定隔离策略.
//指定Hystrix隔离策略为信号量隔离
@HystrixCommand(fallbackMethod = "getUserByIdFallback",
commandProperties ={
@HystrixProperty(name="execution.isolation.strategy",value = "SEMAPHORE")})
@RequestMapping(value = "/user/{id}",method = {RequestMethod.GET})
public String getUserById(@PathVariable("id")int id){
//8081为生产者所占用的端口
//Ribbon会自动的将虚拟主机名映射成服务的网络地址
return restTemplate.getForObject("http://springcloud-provider/user/"+id,String.class);
}
Hystrix的监控机制
Hystrix还提供了监控机制,可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等.
可以通过Actuator监控依赖暴露的/actuator/hystrix.stream端点直观感受.
由于Springboot2以上,Actuator只暴露了/health和/info端点,所以首先需要进行简单配置使其暴露所有端点.
配置application.yml
...
management:
endpoint:
health:
show-details: always # 允许/actuator/health端点显示所有细节
endpoints:
web:
exposure:
include: "*" # Springboot2.0以上手动暴露Actuator所有端点
然后重新启动consumer服务即可.此时,访问http://localhost:8181/actuator/hystrix.stream地址
可以看到,浏览器一直处于加载状态并且在页面上不断的输出"ping:"字符.
这是因为consumer服务中,被注解@HystrixCommand依赖的方法还没被请求执行,所以暂时没有监控数据.
此时,通过浏览器访问http://localhost:8181/user/2地址,请求一次consumer服务所依赖的方法.
再次访问http://localhost:8181/actuator/hystrix.stream地址,查看页面内容变化.
此时,系统会不断地刷新获得到监控数据.但是这样形式的数据让人很难有参考价值.
不过好在Netflix提供了配套的断路器仪表盘,可以将这些数据更直观的展示给用户.
Hystrix Dashboard直观展示Hystrix的监控数据
整合Hystrix Dashboard是一件非常简单的事情.按照以下步骤执行即可:
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
配置启动类
配置application.yml
hystrix:
dashboard:
proxy-stream-allow-list: "*" #防止仪表盘出现【Unable to connect to Command Metric Stream】错误
以上三步执行好后,即可完成对Hystrix Dashboard的整合.此时重启consumer服务.
在浏览器上输入http://localhost:8181/hystrix地址,即可进入仪表盘的主界面.
在最长的那条输入框中输入刚才Hystrix监控数据的地址http://localhost:8181/actuator/hystrix.stream,Title随意输入一个.
然后点击"Monitor Stream"按钮进入数据的直观展示页面.
控制台输出
Hystrix Dashboard数据展示页面
可以看到,Hystrix Dashboard在等待Hystrix输出信息.此时,访问一次http://localhost:8181/user/2地址,使其执行回退.
此时,仪表盘便会显示具体的参数信息.会不停地刷新获取Hystrix的信息.
仪表盘基本参数参考了https://www.cnblogs.com/zouhong/p/12812898.html.
由此,Hystrix便整合了Hystrix Dashboard.
若需要将Hystrix Dashboard单独抽离出来,专门作为一个client执行监控服务,则可以为其创建一个springboot项目搭建.