之前我们是在Zuul
项目中集成Hystrix
的监控,那么我们启动该服务。然后在Hystrix Dashboard中输入: http://localhost:8280/hystrix.stream,然后进行监控,那么我们将看到如下界面:
这说明,Zuul已经整合了Hystrix。
spring-cloud-starter-zuul
本身已经集成了hystrix和ribbon,所以Zuul天生就拥有线程隔离和断路器的自我保护能力,以及对服务调用的客户端负载均衡功能。但是,我们需要注意,当使用path与url的映射关系来配置路由规则时,对于路由转发的请求则不会采用HystrixCommand
来包装,所以这类路由请求就没有线程隔离和断路器保护功能,并且也不会有负载均衡的能力。因此,我们在使用Zuul的时候尽量使用path和serviceId的组合进行配置,这样不仅可以保证API网关的健壮和稳定,也能用到Ribbon的客户端负载均衡功能。
但Zuul的Hystrix监控的粒度是微服务,而不是某个API,也就是所有经过Zuul的请求都会被Hystrix保护起来。假如,我们现在把Product-Service
服务关闭,再来访问会出现什么结果呢?结果可能不是我们所想那样,如下:
在Zuul中实现熔断功能需要实现FallbackProvider接口。该接口有两个方法,一个是getRoute()方法,用于执定熔断器应用于哪些路由服务;另一个方法fallbackResponse()方法为进入熔断功能是执行的逻辑。FallbackProvider 源码如下:
public interface FallbackProvider {
String getRoute();
ClientHttpResponse fallbackResponse(String route, Throwable cause);
}
实现一个针对eureka-client1服务的熔断器,当eureka-client1的服务组出现故障时,进入熔断逻辑,向浏览器输入一句错误的提示信息,代码如下:
@Component
public class NyZuulFallbackProvider implements FallbackProvider {
protected Logger logger = LoggerFactory.getLogger(NyZuulFallbackProvider.class);
@Override
public String getRoute() {
// 注意: 这里是route的名称,不是服务的名称,
// 如果这里写成大写PRODUCT-SERVICE将无法起到回退作用
return "eureka-client1";
}
@Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return 200;
}
@Override
public String getStatusText() throws IOException {
return "OK";
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("error! I'm the fallback.".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
return headers;
}
};
}
}
重新启动工程,关闭eureka-client1的所有实例,早浏览器上访问http://localhost:8777/hello/yang,浏览器显示:
error! I'm the fallback.
如果需要所有的路由服务都加熔断功能,只需要在getRoute()方法上返回“*”的匹配府,代码如下:
@Override
public String getRoute() {
return "*";
}