在微服务架构中,是将一个个业务功能拆分成一个个小的服务,各个服务之间通过IPC机制进行通信,因此有可能因为网络故障或依赖服务自身问题出现延迟或调用故障。若此时调用方不断增加请求,最后就会出现因等待依赖服务响应而造成任务积压,最终导致自身服务的瘫痪。为了解决这个问题,Spring Cloud给出了断路器模式。

什么是断路器?

  断路器的概念原本是应用在电路上的,断路器是一种开关装置,用于保护线路过载。当电路中有电器发生短路,断路器能及时切断故障电路,避免发生过载、过热甚至起火等严重后果。

  在微服务架构中,断路器也起到了一个类似这样的作用。当某个服务发生故障时,通过断路器的故障监控,向调用方返回一个设定的错误响应,以防止调用方长期等待。这样可以避免线程因服务故障而被长期占用不能释放,从而避免故障蔓延。

Spring Cloud的断路器实现

  在Spring Cloud中,使用Hystrix来实现断路器的功能。Hystrix旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。

Hystrix的实现

  这里需要用到前面服务注册与消费的例子。

  依次启动注册中心服务,compute-service服务以及Ribbon客户端服务,并访问http://localhost:3333/add ,此时可以看到页面返回计算结果30。现在通过关闭compute-service来模拟服务出现故障的情况,关闭compute-service服务之后,再次访问http://localhost:3333/add ,会得到如下图所页的错误提示:

接下来修改Ribbon客户端来增加Hystrix功能。
1.加入Hystrix依赖。

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

2.向主入口程序添加@EnableCircuitBreaker注解开启断路器功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class RibbonApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}

3.在服务消费方法上添加@HystrixCommand注解来指定失败回调方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class ComputeService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "addServiceFallback")
public String addService() {
return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();
}
public String addServiceFallback() {
return "error";
}
}
  • 此例子中指定失败回调方法为addServiceFallback(),该方法返回字符串”error”

4.重启Ribbon服务,再次访问http://localhost:3333/add ,此时得到返回的错误字符串”error”。

这说明了Hystrix功能起了作用,加入了这个功能之后,就可以设定不同的错误返回来应对不同的错误场景,提高应用的效率以及用户体验。

解决加入Hystrix后第一次请求失败

  在实现Hystrix的过程中,发现了一个问题,就是在加入了Hystrix之后,第一次通过访问http://localhost:3333/add 来消费服务的时候,会返回“error”错误信息,再次刷新之后才会显示正确的结果,而且之后的访问都是正常的。

  造成这个问题的原因是什么呢?上网找了一下,原因在于Hystrix的默认超时时间为1秒,而第一次请求因为懒加载机制以及一些类的实例化,使得响应时间往往会大于1秒,这就会使用Hystrix因为超时而进入到错误回调函数,因此会返回错误结果。因此可以通过配置超时时间或禁用Hystrix超时来解决这个问题。

  • 配置超时时间方法:在application.properties中添加以下配置信息

    1
    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000 //配置超时时间为5秒
  • 禁用Hystrix超时:在application.properties中添加以下配置信息

    1
    hystrix.command.default.execution.timeout.enabled: false

  以上的两个方法要根据应用的实际情况,谨慎选择。



参考链接:
Spring Cloud构建微服务架构(三)断路器