Hystrix是什么
在微服务架构中,我们是将一个单体应用拆分成多个服务单元,各个服务单元之间通过注册中心彼此发现和消费对方提供的服务,每个服务单元都是单独部署,在各自的服务进程中运行,服务之间通过远程调用实现信息交互,那么当某个服务的响应太慢或者故障,又或者因为网络波动或故障,则会造成调用者延迟或调用失败,当大量请求到达,则会造成请求的堆积,导致调用者的线程挂起,从而引发调用者也无法响应,调用者也发生故障。
比如电商中的用户下订单,我们有两个服务,一个下订单服务,一个减库存服务,当用户下订单时调用下订单服务,然后下订单服务又调用减库存服务,如果减库存服务响应延迟或者没有响应,则会造成下订单服务的线程挂起等待,如果大量的用户请求下订单,或导致大量的请求堆积,引起下订单服务也不可用,如果还有另外一个服务依赖于订单服务,比如用户服务,它需要查询用户订单,那么用户服务查询订单也会引起大量的延迟和请求堆积,导致用户服务也不可用。
所以在微服务架构中,很容易造成服务故障的蔓延,引发整个微服务系统瘫痪不可用。
为了解决此问题,微服务架构中引入了一种叫熔断器的服务保护机制。
熔断器也有叫断路器,他们表示同一个意思,最早来源于微服务之父Martin Fowler的论文CircuitBreaker一文。“熔断器”本身是一种开关装置,用于在电路上保护线路过载,当线路中有电器发生短路时,能够及时切断故障电路,防止发生过载、发热甚至起火等严重后果。
微服务架构中的熔断器,就是当被调用方没有响应,调用方直接返回一个错误响应即可,而不是长时间的等待,这样避免调用时因为等待而线程一直得不到释放,避免故障在分布式系统间蔓延;
Spring Cloud Hystrix实现了熔断器、线程隔离等一系列服务保护功能。该功能也是基于Netflix的开源框架Hystrix实现的,该框架的目标在于通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。
在SpringCloud中使用熔断器Hystrix是非常简单和方便的,只需要简单两步即可:
1、添加依赖
<!--Spring Cloud熔断器起步依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
2、在入口类中使用@EnableCircuitBreaker注解开启断路器功能,也可以使用一个名为@SpringCloudApplication的注解代替主类上的三个注解;
3、在调用远程服务的方法上添加注解:@HystrixCommand(fallbackMethod="error")
hystrix默认超时时间是1000毫秒,如果你后端的响应超过此时间,就会触发断路器;
修改hystrix的默认超时时间:
@HystrixCommand(fallbackMethod="error", commandProperties={
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="1500")}) //熔断器,调用不通,回调error()方法
public String webHello () {
Hystrix的服务降级
有了服务的熔断,随之就会有服务的降级,所谓服务降级,就是当某个服务熔断之后,服务端提供的服务将不再被调用,此时由客户端自己准备一个本地的fallback回调,返回一个默认值来代表服务端的返回;
这种做法,虽然不能得到正确的返回结果,但至少保证了服务的可用,比直接抛出错误或服务不可用要好很多,当然这需要根据具体的业务场景来选择;
我们在调用服务提供者时,我们自己也有可能会抛异常,默认情况下方法抛了异常会自动进行服务降级,交给服务降级中的方法去处理;
当我们自己发生异常后,只需要在服务降级方法中添加一个Throwable类型的参数就能够获取到抛出的异常的类型,如下:
public String error(Throwable throwable) {
System.out.println(throwable.getMessage());
return "error";
}
此时我们可以在控制台看到异常的类型;
如果远程服务有一个异常抛出后我们不希望进入到服务降级方法中去处理,而是直接将异常抛给用户,那么我们可以在@HystrixCommand注解中添加忽略异常,如下:
@HystrixCommand(fallbackMethod="error", ignoreExceptions = Exception.class)
自定义Hystrix请求的服务异常熔断处理
我们也可以自定义类继承自HystrixCommand来实现自定义的Hystrix请求,在getFallback方法中调用getExecutionException方法来获取服务抛出的异常;
com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(""))
Hystrix仪表盘(Hystrix Dashboard),就像汽车的仪表盘实时显示汽车的各项数据一样,Hystrix仪表盘主要用来监控Hystrix的实时运行状态,通过它我们可以看到Hystrix的各项指标信息,从而快速发现系统中存在的问题进而解决它。
要使用Hystrix仪表盘功能,我们首先需要有一个Hystrix Dashboard,这个功能我们可以在原来的消费者应用上添加,让原来的消费者应用具备Hystrix仪表盘功能,但一般地,微服务架构思想是推崇服务的拆分,Hystrix Dashboard也是一个服务,所以通常会单独创建一个新的工程专门用做Hystrix Dashboard服务;
第一步:创建一个普通的Spring Boot工程
比如创建一个名为springcloud-hystrix-dashboard的Spring Boot工程,建立好基本的结构和配置;
第二步:添加相关依赖
在创建好的Spring Boot项目的 pom.xml文件中添加相关依赖,如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
第三步:入口类上添加注解
添加好依赖之后,在入口类上添加@EnableHystrixDashboard注解开启仪表盘功能,如下:
@SpringBootApplication
@EnableHystrixDashboard
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
第四步:属性配置
最后,我们可以根据个人习惯配置一下application.properties文件,如下:server.port=3721
至此,我们的Hystrix监控环境就搭建好了;
Hystrix仪表盘工程已经创建好了,现在我们需要有一个服务,让这个服务提供一个路径为/actuator/hystrix.stream接口,然后就可以使用Hystrix仪表盘来对该服务进行监控了;
我们改造消费者服务,让其能提供/actuator/hystrix.stream接口,步骤如下:
1、消费者项目需要有hystrix的依赖:
<!--Spring Cloud熔断器起步依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
2、需要有一个spring boot的服务监控依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
3、配置文件需要配置spring boot监控端点的访问权限:
management.endpoints.web.exposure.include=*
这个是用来暴露 endpoints 的,由于 endpoints 中会包含很多敏感信息,除了 health 和 info 两个支持直接访问外,其他的默认不能直接访问,所以我们让它都能访问,或者指定:
management.endpoints.web.exposure.include=hystrix.stream
4、访问入口 http://localhost:8081/actuator/hystrix.stream
注意:这里有一个细节需要注意,要访问/hystrix.stream接口,首先得访问consumer工程中的任意一个其他接口,否则直接访问/hystrix.stream接口时会输出出一连串的ping: ping: …,先访问consumer中的任意一个其他接口,然后再访问/hystrix.stream接口即可;