一、Hystrix简介
在微服务架构中,我们将系统拆分成了一个个的服务单元,各单元间通过服务注册与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会出现因等待出现故障的依赖方响应而形成任务积压,最终导致自身服务的瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
断路器(Circuit Breaker)模式: 为了解决上述问题,因此产生了断路器模式。
断路器本身是一种开关装置,用于在电路上保护线路过载,当线路中有电器发生短路时,“断路器”能够及时的切断故障电路,防止发生过载、发热、甚至起火等严重后果。
在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。在Spring Cloud中使用了Hystrix 来实现断路器的功能。接着我们使用前面创建的项目分别在服务消费断Ribbn与Feign中使用断路由模式:
二、在Ribbon中集成Hystrix断路由
2.1 pom中增加Hystrix依赖
改造上节中ribbon-consumer 工程的代码,首先在pox.xml文件中加入spring-cloud-starter-netflix-hystrix的起步依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.2 加@EnableHystrix注解
在springboot启动类中 加@EnableHystrix注解开启Hystrix:
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class RibbonConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonConsumerApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
2.3 改造HelloService类
改造HelloService类,在hiService方法上加上@HystrixCommand注解。该注解对该方法创建了熔断器的功能,并指定了fallbackMethod熔断方法,熔断方法直接返回了一个字符串,字符串为”hi,”+name+”,sorry,error!”,代码如下:
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiError")
public String hiService(String name) {
return restTemplate.getForObject("http://eureka-client/hello",String.class);
}
//Fall Back method
public String hiError(String name) {
return "hi,"+name+",sorry,error!";
}
}
2.4 验证结果
启动注册中心,启动ribbon-consumer,当我们访问http://localhost:8083/hi/payne,浏览器显示:
可以看到,当外部接口不能访问的时候,程序直接调用fallback指定的方法返回结果,从而不需要阻塞当前线程,从而导致访问请求一直处于等待
当启动eureka-client,再次访问的时候
hi ,i am from port:8081
三、Feign中使用断路器-fallback
3.1 Enable Hystrix
Feign是自带断路器的,因此不需要人为引用Hystrix依赖包,但是设置
feign.hystrix.enabled=true
注意:properties文件可能不自动提示feign.hystrix.enabled
3.2 FeignClient接口改造
基于feign-consumer工程进行改造,只需要在FeignClient的HelloService接口的注解中加上fallback的指定类就行了:
@FeignClient(value = "eureka-client",fallback = FallBackHelloService.class)
public interface HelloService {
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String hiService();
}
3.3 添加FallBack指定类
FallBackHelloService需要实现HelloService 接口,并注入到Ioc容器中,代码如下:
@Component
public class FallBackHelloService implements HelloService{
@Override
public String hiService() {
return "Sorry,this is fall back method";
}
}
3.4 验证结果
访问地址: http://localhost:8084/hi
打开eureka-client工程,再次访问,浏览器又返回正常结构,说明我们的断路由已经生效。
四、Feign中使用断路器-fallbackFactory
4.1 添加FallBackFactory指定类
FallBackFactory类需要实现FallbackFactory接口,传入泛型对应的service客户端,并覆盖对应方法,返回service客户端对象。
@Component
public class ClientFallBackFactory implements FallbackFactory<HelloService>{
private static Logger LOGGER = LoggerFactory.getLogger(ClientFallBackFactory.class);
@Override
public HelloService create(Throwable throwable) {
LOGGER.error("Fall Back Error,"+throwable.getMessage(),throwable);
return new HelloService(){
@Override
public String hiService() {
return "Sorry,this fall back from FallBackFactory";
}
};
}
}
4.2 指定FallBackFactory
添加指定类fallbackFactory = ClientFallBackFactory.class
@FeignClient(value = "eureka-client",fallbackFactory = ClientFallBackFactory.class)
public interface HelloService {
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String hiService();
}
验证之后 ,可以看到同样的效果