1.Hystrix概述
1.1.什么是Hystrix
Hystrix是一个用于处理分布式系统的延迟和容错的开源库。Hystrix主要用于处理分布式系统中复杂多变的服务依赖调用失败、超时、异常等情况,保证一个服务依赖出问题的情况下,提供一个服务预期的、可处理的备选响应(FallBack),避免微服务整体级联故障,以提高分布式系统的弹性。
1.2.Hystrix的作用是什么
Hystrix旨在执行以下操作:
- 提供保护并控制延迟和失败,以及通过第三方客户端库(通常是通过网络)访问依赖项导致的失败。
- 切断复杂的分布式系统中的级联故障。
- 快速响应并快速恢复。
- 回退并在可能的情况下正常降级。
- 启用近乎实时的监视,警报和操控。
1.3.Hystrix能解决什么问题
Hystrix在分布式项目中主要用于处理:
- 服务降级
- 服务熔断
- 服务限流
- 接近实时地监控
2.Hystrix服务熔断
2.1.服务熔断机制
首先对应服务熔断我们要理解“服务雪崩”的概念,服务雪崩是多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,就是所谓的“雪崩”。
熔断机制是应对雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,就会通过熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。
2.2.简单实现一个Hystrix熔断
在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。
这里我们还是基于我们之前博客的微服务项目springcloud-provider-dept-8001 服务端 复制一份作为hystrix的微服务项目。
①添加hystrix pom.xml依赖包:
<!--引入hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency>
②修改application.yml配置,修改了实例名称:
server:
port: 8001
##省略了数据库连接信息与mybatis配置
#eureka的配置,确定客户端服务注册到eureka服务列表内
eureka:
client:
service-url:
#集群配置
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
#defaultZone: http://localhost:7001/eureka/
instance:
instance-id: springcloud-provider-dept-hystrix-8001 #修改eureka上默认的服务描述信息
prefer-ip-address: true #访问路径可以显示ip地址
③基于Controller层的调用方法通过id获取Dept用户来做异常判定:
@RestController @RequestMapping("/dept") public class DeptController { @Autowired private DeptService service; @GetMapping("/queryById/{id}") /*@HystrixCommand表示一旦调用服务方法失败并抛出了异常信息之后, 会自动调用@HystrixCommand标注好的fallbackMethod中指定名称的方法*/ @HystrixCommand(fallbackMethod = "processHystrixGet") public Dept queryById(@PathVariable("id") Long id){ Dept dept = service.queryById(id); //模拟当查询不到id或者id信息异常时返回错误异常的提示 if(null == dept){ throw new RuntimeException("id=>" + id + "不存在该用户,或者用户信息无法找到!"); } return dept; }; //熔断备选方法:异常回调信息显示 public Dept processHystrixGet(@PathVariable("id") Long id){ return new Dept() .setDeptno(id) .setDname("id=>" + id + "没有对应的信息,null--@Hystrix") .setDbSource("no this database in MySQL"); } }
④在主启动类上添加对hystrix的熔断机制的支持:
@SpringBootApplication @EnableEurekaClient //在服务启动后自动注册到eureka中 @EnableDiscoveryClient //服务发现 @EnableCircuitBreaker //启用对hystrix的熔断机制的支持 public class DeptProvider8001_Hystrix_App { public static void main(String[] args) { SpringApplication.run(DeptProvider8001_Hystrix_App.class, args); } }
⑤启动Eureka客户端、Hystrix服务端进行访问验证:
访问正常存在的服务id,能返回正常数据:
访问异常不存在的id时,返回fallback方法中的信息:
可以看出,当执行调用某个微服务发生异常时,Hystrix能通过自定义的fallbackMethod做异常的错误返回,快速进行异常熔断机制。
服务熔断是在服务运行的情况下,对于服务内部执行错误的异常情况的一种处理方式。
3.Hystrix服务降级
3.1.服务降级机制
服务降级是从网站整体的负载考虑,当某个服务在某一时间内承受大量的服务请求,而需要极大的资源消耗,需要关闭当前系统的某些服务,做资源的扩充。牺牲单个服务的运行,当再次访问这单个服务的时候,通过服务降级处理,返回给客户设定的默认缺省值。
相当于弃军保帅,维护的是整个系统的可用性。
3.2.简单实现服务降级
服务降级这里从客户端进行实现。
(1)首先在springcloud-api中定义一个降级之后的回调函数类,实现FalllbackFactory接口,接口中实现了对应请求信息的异常处理方法:
@Component //注意不要忘记添加,需要把类加载进Spring容器中才能获取到 public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService> { @Override public DeptClientService create(Throwable throwable) { return new DeptClientService() { @Override public boolean addDept(Dept dept) { return false; } @Override public Dept queryById(Long id) { return new Dept().setDeptno(id).setDname("该ID:" + id + "没有对应的信息,Consumer客户端提供的降级信息,此刻服务provider已经关闭"). setDbSource("no this database in MySQL"); } @Override public List<Dept> queryAll() { return null; } }; } }
(2)对应api接口中使用fallabckFatory去指定调用的是哪个class实现类:
//value中对应服务提供方的名字 //服务降级:表示DeptClientService当前接口中任何一个方法出了问题:都去找DeptClientServiceFallbackFactory回调处理 @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT", fallbackFactory = DeptClientServiceFallbackFactory.class) @Component //注入到容器中 public interface DeptClientService { /** * 接口中的三个方法对应服务提供者的三个方法 * 这里面的接口对应服务提供者的controller接口,名称必须一致,然后接口的Mapping映射url必须一致 * @param dept * @return */ @PostMapping("/dept/add") public boolean addDept(Dept dept); @GetMapping("/dept/queryById/{id}") public Dept queryById(@PathVariable("id") Long id); @GetMapping("/dept/queryAll") public List<Dept> queryAll(); }
(3)基于FeignClinet调用,则需要修改服务提供者中application.yml,开启feign中对hystrix的支持:
#开启降级feign.hystrix支持 feign: hystrix: enabled: true
(4)测试验证:
步骤:启动三个Eureka注册中心7001、7002、7003,启动provider-dept-8001作为服务提供者、启动consumer-dept-feign服务消费者:
可以看到服务提供者已经注册进去并正常运行:
通过客户端consumer-feign的81端口也能访问到对应的id数据:
(5)模拟服务熔断异常:
关闭服务提供方provider-dept-8001,同时访问81端口的数据请求:
可以看到此时调用到了我们编写的fallbackFactory中的回调方法显示降级信息。
所以即使服务关闭之后,Hystrix的服务熔断机制也能避免大量重复无效访问带来的服务异常,能较好的提供客户体验。
本节涉及实例及相关代码已上传至github:
https://github.com/devyf/SpringCloud_Study/tree/main/springcloud_hello