什么是Hystrix?
在分布式系统中,服务与服务之间的依赖错综复杂,一种不可避免的情况就是某些服务会出现故障,导致依赖于它们的其他服务出现远程调度的线程阻塞。Hystrix提供了熔断器功能,能够阻止分布式系统中出现联动故障,通过隔离服务的访问点阻止联动故障的,并提供了故障的解决方案,从而提高 了整个分布式系统的弹性。
简单来说:微服务架构中存在很多的服务,例如A、B、C、D、E5个服务,并且对于一次调用来说,并不仅仅是访问一个服务,按照功能划分来说,每个服务做得事情是单一的,所以大部分的请求都是类似于A-C-E,跨过多个服务。
如果单个服务的正常运行几率为99.00%(机房的不可靠性、运营商的不可靠性等等),那么对于A-C-E调用流程来说,几率为99.00%*99.00%*99.00%=97.03%,也就意味着10000次请求有300多次会失败,问题还是比较严重的。
Hystrix设计原则
Hystrix工作机制
使用方法
1、在RestTemplate和Ribbon上使用熔断器
找到本人之前的eureka-consumer项目,gitbub地址:https://github.com/ali-mayun/eureka-consumer
新加依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.1.1.RELEASE</version> </dependency>
运行主类:
package com.ty.eurekaconsumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; @EnableEurekaClient @SpringBootApplication //使用这注解开启hystrix的功能 @EnableHystrix public class EurekaConsumerApplication { public static void main(String[] args) { SpringApplication.run(EurekaConsumerApplication.class, args); } }
更改之前的service
package com.ty.eurekaconsumer.service; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.client.RestTemplate; @Service public class RibbonService { @Autowired private RestTemplate restTemplate; //使用@HystrixCommand注解启用熔断器的功能,当服务熔断后,将不调用远程服务,直接调用本地的handleError方法 @HystrixCommand(fallbackMethod = "handleError") public String hiService(String name) { return restTemplate.getForObject("http://eureka-provider/firstCall?name=" + name, String.class); } public String handleError(String name) { return name + "在访问远程服务时,被熔断了,调用本地的方法"; } }
现在启动eureka-server、eureka-consumer两个项目,不启动eureka-provider,制造服务不能用的假象,运行效果如下:
2、在feign上使用熔断器
上面一种方式相对来说还是比较麻烦的,使用feign则方便很多。
打开上篇博文中的eureka-feign-consumer项目,github地址:https://github.com/ali-mayun/eureka-feign-consumer
修改application.properties文件,开启Hystrix功能:
# 服务名称 spring.application.name=eureka-feign-consumer # 端口号 server.port=4001 # 服务注册中心地址 eureka.client.serviceUrl.defaultZone=http://localhost:1001/eureka/ # 增加Hystrix功能 feign.hystrix.enabled=true
更改EurekaClientFeign:
package com.ty.eurekafeignconsumer.service; import com.ty.eurekafeignconsumer.config.FeignConfig; import com.ty.eurekafeignconsumer.hystrix.BaseHystrix; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; //新增fallback属性指定出现熔断由哪个类来处理。 @FeignClient(value = "eureka-provider", configuration = FeignConfig.class, fallback = BaseHystrix.class) public interface EurekaClientFeign { //只需要在接口中定义方法即可。调用eureka-provider服务的firstCall方法,并且feign集成了Ribbon @GetMapping(value = "/firstCall") String sayHiFromClientEureka(@RequestParam("name") String name); }
BaseHystrix:
package com.ty.eurekafeignconsumer.hystrix; import com.ty.eurekafeignconsumer.service.EurekaClientFeign; import org.springframework.stereotype.Component; //熔断处理类需要实现调用远程服务的service,例如本案例在EurekaClientFeign类中调用远程服务,就需要实现此接口, //然后相同名字的方法就可以一一对应 @Component(value = "baseHystrix") public class BaseHystrix implements EurekaClientFeign { @Override public String sayHiFromClientEureka(String name) { return name + "访问的远程服务被熔断"; } }
controller中有个坑,就是EurekaClientFeign是一个接口,主类中使用@EnableFeignClients开启了feign功能,该注解会扫描@FeignClient,将使用到该注解的接口通过动态代理的方式创建类,因此EurekaClientFeign接口就会有两个实现类。
另一个是BaseHystrix,用来处理发生熔断后的逻辑,因此这里使用@Autowired就出错了,但是使用@Resource就ok,但是暂不清楚为啥会正确的找到动态代理生成的那个类,后续研究。。。
package com.ty.eurekafeignconsumer.controller; import com.ty.eurekafeignconsumer.service.EurekaClientFeign; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController public class FeignController { //这个地方有点坑,因为EurekaClientFeign已经有另外一个实现类就是BaseHystrix,使用@Autowired会报错 //不过暂时不清楚@Resource会注入正确的bean,后续待研究。。。 @Resource private EurekaClientFeign eurekaClientFeign; @GetMapping("/hi") public String sayHi(@RequestParam(value = "name", defaultValue = "马云", required = false) String name) { return eurekaClientFeign.sayHiFromClientEureka(name); } }
当eureka-provider正常开启,效果如下:
关闭eureka-provider,访问效果如下:
spring cloud深入学习(五)-----熔断器Hystrix
原文:https://www.cnblogs.com/alimayun/p/10841541.html