前面我们已经解决了微服务的 服务注册、负载均衡、动态路由、服务调用等基本功能,这里我们考虑另外一个问题:我们不同的服务是部署在不同的节点上的,如果我们其中的一个节点因为故障或者网络的原因造成我们服务消费者在消费的时候出现问题会出现什么情况呢!说的再简单点就是我们调用的服务出现了问题会不会影响我们调用者自身的正常运行呢,这个答案是肯定的。当我们的服务出现问题,然而我们再编程的时候还没有做出处理,那么就会出现我们下面提到的服务雪崩的问题。服务雪崩是由于一个服务出现的问题造成了连锁的反应,那有没有解决这个问题的办法呢,当然是有的,spring Cloud为我们提供了hystrix来解决这个问题。
首先看一下官网对于hystrix的定义与介绍
A service failure in the lower level of services can cause cascading failure all the way up to the user. When calls to a particular service exceed circuitBreaker.requestVolumeThreshold (default: 20 requests) and the failure percentage is greater than circuitBreaker.errorThresholdPercentage (default: >50%) in a rolling window defined by metrics.rollingStats.timeInMilliseconds (default: 10 seconds), the circuit opens and the call is not made. In cases of error and an open circuit, a fallback can be provided by the developer.
这段话的大概意思就是一个底层的服务出现问题会导致上层调用他的服务也出现问题,而hystrix则提供了一种回退机制,在预定时间内没有返回时会返回一个默认值。这个预定时间的默认值是10秒
下面开始为我们的服务添加断路器保护,首先需要引入相应的依赖,注意,这里要在调用方添加断路器而不是被调用方。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
然后在启动类上添加注解@EnableCircuitBreaker,然后我们就要写我们的断路器方法,断路器方法很简单,其实就是在方法上加一个注解,然后指定哪个方法为我们提供断路器保护,具体代码如下所示:
@GetMapping("/index1")
@HystrixCommand(fallbackMethod = "defaultMethod")
public String index1(){
try {
Thread.sleep(10000);
}catch (Exception e){
e.getStackTrace();
}
return "index1";
}
public String defaultMethod(){
return "defaultMethod";
}
我在controller的index1方法上添加了@HystrixCommand(fallbackMethod = "defaultMethod")注解,并且指定了我们的断路器执行的方法为defaultMethod方法,然后使用线程让当前方法休眠10秒钟,当我们调用index1接口的时候会返回defaultMethod的返回值,这样我们就完成了最初级的断路器保护。
这时候会有人觉着这样写起来很麻烦,下面说一种更加简洁的写法。我们在进行服务间调用的时候使用的是feign进行声明式的接口调用,而feign我们是在调用方定义了一个接口,然后指定了这个接口具体要调用哪个微服务,了解了这些之后我们可以直接实现我们声明的fegin接口,然后实现接口中的各个方法,具体代码如下所示:
@Component
public class ProviderIndexFallback implements ProviderIndex {
@Override
public String index() {
return "ProviderIndexFallback index";
}
}
@FeignClient(name="provider",fallback = ProviderIndexFallback.class)
public interface ProviderIndex {
@RequestMapping(method = RequestMethod.GET, value = "/index")
String index();
}
上面我们实现了我们调用其他服务的feign接口并实现类注册到了spring容器中,然后在feign接口的注解上指定了我们刚刚实现的类,然后当我们被调用方出现问题时,就会在这里返回默认值,即实现类中的方法返回值。
在用feign和hystrix结合使用的时候要注意在yml配置文件中一定要开启feign对hystrix的支持,否则上面的配置则无法生效,我自己在这里就踩了一个小坑,具体的配置如下:
feign:
hystrix:
enabled: true