Hystrix是什么
在微服务架构中,我们是将一个单体应用拆分成多个服务单元,各个服务单元之间通过注册中心彼此发现和消费对方提供的服务,每个服务单元都是单独部署,在各自的服务进程中运行,服务之间通过远程调用实现信息交互,那么当某个服务响应太慢或者故障,又或者因为网络波动或者故障,则会造成调用者延迟或者调用失败,当大量请求到达,则会造成请求的堆积,导致调用者的线程挂起,从而引发调用者也无法响应,调用者也发生故障。
比如电商中的用户下单,我们有两个服务,一个下订单服务,一个减库存服务,当用户下订单时调用下订单服务,然后下订单服务又调用减库存服务,如果减库存服务响应延迟或者没有响应,则会造成下订单服务的线程挂起等待,如果大量的用户请求下订单,或导致大量的请求堆积,引起下订单服务也不可用,如果还有另外一个服务依赖于下订单服务,比如用户服务,它需要查询用户订单,那么用户服务查询订单也会引起大量的延迟和请求堆积,导致用户服务也不可用。
所以在微服务架构中,很容易造成服务故障的蔓延,引发整个微服务系统瘫痪不可用。
为了解决这个问题,微服务架构中引入了一种叫熔断器的服务保护机制。
熔断器也有叫断路器,表示同一个意思,本身是一种开关部署,用于在电路上保护线路过载。
微服务架构中的熔断器,就是当被调用方没有响应,向调用方直接返回一个错误响应即可,而不是长时间的等待,这样避免调用时因为等待而线程一直得不到解放,避免故障在分布式系统中蔓延。
SpringCloud Hystrix实现了熔断器、线程隔离等一系列服务保护功能,该功能也是基于Netflix的开源框架Hystrix实现的,该框架的目标在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力,Hystrix具备服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。
Hystrix快速入门
在SpringCloud中使用熔断器Hystrix是非常简单和方便的,只需要简单两步即可:
1、添加依赖(在服务消费者的pom.xml文件中添加)
<!--Spring Cloud熔断器起步依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.9.RELEASE</version> </dependency>
2、在入口类中使用@EnableHystrix注解开启熔断器功能,也可以使用一个名为@SpringCloudApplication的注解代替主法上的三个注解:
@SpringBootApplication // SpringBoot 注解支持 @EnableEurekaClient // 开启eureka客户端支持 @EnableHystrix // 开启熔断器功能
3、在调用远程服务的方法上添加注解:
// 表示发生熔断之后调用error方法 @HystrixCommand(fallbackMethod = "error") // 对本方法开启熔断器功能
在服务消费者中添加方法:
@RequestMapping("/web/hystrix")
// 表示发生熔断之后调用error方法
@HystrixCommand(fallbackMethod = "error") // 对本方法开启熔断器功能
public String hystrix(){
// 逻辑判断省略不写
return restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/hello",String.class).getBody();
}
public String error(){
// 访问远程服务失败,该如何处理?这些处理逻辑就可以写在该方法中
return "error";
}
服务消费者Hystrix测试
hystrix默认超时时间是1000毫秒,如果后端的响应超过此时间,就会触发断路器;
修改hystrix的默认超时时间:
@RequestMapping("/web/hystrix")
// 表示发生熔断之后调用error方法 调用服务提供者的方法超时15s之后熔断,然后调用error方法
@HystrixCommand(fallbackMethod = "error",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "15000")
}) // 对本方法开启熔断器功能
public String hystrix(){
// 逻辑判断省略不写
return restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/hello",String.class).getBody();
}
public String error(){
return "error";
}
Hystrix的服务降级
有了服务的熔断,随之就会有服务的降级,所谓服务降级,就是当某个服务熔断之后,服务端提供的服务将不会再被调用,此时客户端自己准备一个本地的fallback回调,返回一个默认值来代表服务端的返回;
这种做法,虽然不能得到正确的返回结果,但是至少保证了服务的可用,比直接抛出错误或者服务不可用要好很多,当然这需要根据具体的业务场景来选择;
Hystrix的异常处理
在调用服务提供者的时候,本身也有可能会抛异常,默认情况下方法抛了异常会自动进行服务降级,交给服务降级中的方法去处理;
当自己发生异常后,只需要在服务降级方法中添加一个Throwable类型的参数就能够获取抛出的异常的类型,如下:
@RequestMapping("/web/hystrix")
// 表示发生熔断之后调用error方法 调用服务提供者的方法超时15s之后熔断,然后调用error方法
@HystrixCommand(fallbackMethod = "error",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "15000")
}) // 对本方法开启熔断器功能
public String hystrix(){
// 逻辑判断省略不写
int a = 10/0; // 本身有异常
return restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/hello",String.class).getBody();
}
public String error(Throwable throwable){
System.out.println(throwable.getMessage());
return "error";
}
此时可以在控制台看到异常的类型;
如果远程服务有一个异常抛出后我们不希望进入到服务降级方法中去处理,而是直接将异常抛给用户,那么可以在@HystrixCommand注解中添加忽略异常ignoreExceptions = RuntimeException.class,如下:
@HystrixCommand(fallbackMethod = "error",ignoreExceptions = RuntimeException.class, commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "15000") })
自定义Hystrix请求的服务异常熔断处理
我们也可以自定义继承自HystrixCommand来实现自定义的Hystrix请求,在getFallback方法中调用getExecutionException方法来获取服务抛出的异常;
在服务消费者中新建一个类:
package com.lavender.springcloud.hystrix;
import com.netflix.hystrix.HystrixCommand;
import org.springframework.web.client.RestTemplate;
/**
* 自定义Hystrix请求
*/
public class MyHystrixCommand extends HystrixCommand<String> {
private RestTemplate restTemplate;
public MyHystrixCommand(Setter setter, RestTemplate restTemplate){
super(setter);
this.restTemplate = restTemplate;
}
@Override
protected String run() throws Exception {
// 调用远程的服务
return restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/hello",String.class).getBody();
}
/**
* 当上面run()方法中调用远程服务超时、异常、不可用等情况时,会触发该熔断/降级方法
* @return
*/
@Override
public String getFallback() {
// 远程调用服务出现异常或者本身有异常都会捕捉到
Throwable throwable = super.getExecutionException();
System.out.println(throwable.getMessage());
// 实现服务熔断/降级逻辑
return "error";
}
}
在服务消费者中添加方法进行测试:
@RequestMapping("/web/hystrix2")
// 表示发生熔断之后调用error方法 调用服务提供者的方法超时15s之后熔断,然后调用error方法
public String hystrix2() throws ExecutionException, InterruptedException {
// 逻辑判断省略不写
MyHystrixCommand myHystrixCommand = new MyHystrixCommand(com.netflix.hystrix.HystrixCommand.Setter.
withGroupKey(HystrixCommandGroupKey.Factory.asKey("")),restTemplate);
// 同步调用(该方法执行后,会等待远程的返回结果,拿到了远程的返回结果,该方法才返回,然后代码继续往下执行)
// String string = myHystrixCommand.execute(); // 如果调用远程服务没问题,返回run()中结果,如果有问题,getFallback()中结果
// return string;
// 异步调用,该方法执行后,不会马上有远程的返回结果,将来会有结果
Future<String> future = myHystrixCommand.queue();
// 写一些业务的逻辑
// 阻塞的方法,直到拿到结果
String string = future.get();
// 可以再写一些业务逻辑
return string;
}
Hystrix仪表盘监控
Hystrix仪表盘(Hystrix Dashboard),就像汽车的仪表盘实时显示汽车的各项数据一样,Hystrix仪表盘主要用来监控Hystrix的实时运行状态,通过它我们可以看到Hystrix的各项指标信息,从而快速发现系统中存在的问题进而解决它。
要是用Hystrix仪表盘功能,首先需要有一个Hystrix Dashboard,这个功能我们可以在原来的消费者应用上添加,让原来的消费者具有Hystrix仪表盘功能,但是一般的,微服务架构的思想是推崇服务的拆分,Hystrix Dashboard也是一个服务,所以通常会单独创建一个新的工程专门用做Hystrix Dashboard服务。
搭建一个Hystrix Dashboard服务的步骤
第一步:创建一个普通的Spring Boot工程
第二步:添加相关依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> <version>1.4.5.RELEASE</version> </dependency>
第三步:入口类添加注解
添加好依赖之后,在入口类上添加@EnableHystrixDashboard
第四步:属性配置
最后,可以根据个人习惯配置一下application.properties文件,如下:server.port=3721
至此,hystrix监控环境就搭建好了