Zuul的容错与回退
在Spring Cloud中,Zuul默认已经整合了Hystrix。首先我们结合前面的项目做一个简单的实验。
1.启动项目
(1)启动cloud-discovery-enreka,port=8001
(2)启动cloud-register-user,port=8002
(3)启动cloud-register-gateway-zuul,port=8023
(4)启动cloud-hystrix-dashboard,port=8019
2.测试
(1)访问http://localhost:8023/cloud-register-user/1,即可获取正常结果
(2)访问http://localhost:8023/hystrix.stream,即可获取Hystrix的监控数据
(3)访问http://localhost:8019/hystrix,并在监控地址栏填入http://localhost:8023/hystrix.stream,即可获取如下结果
由图可知,Zuul的Hystrix监控的粒度是微服务,而不是某个API;同时也说明,所有经过Zuul的请求,都会被Hystrix保护起来。
(4)关闭项目cloud-register-user,再次访问http://localhost:8023/cloud-register-user/1
页面显示:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sun Oct 21 11:41:09 CST 2018
There was an unexpected error (type=Internal Server Error, status=500).
TIMEOUT
实验结束,发生异常以上面形式展示,这么显示是不是太low了,接下来,我们看看zuul如何处理这个问题,显得高大上一点。
Zuul实现回退
1.复制项目
复制cloud-register-gateway-zuul微服务修改为cloud-register-gateway-zuul微服务
2.编写zuul回退类
package com.midou.cloud.register.gateway.zuul.fallback;
import com.netflix.hystrix.exception.HystrixTimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
/**
* @author midou
* @description
* @date 2018/10/21 11:54
* @modified by
*/
@Component
public class MyFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
// 表明是为哪个微服务提供回退,*表示为所有微服务提供回退
return "*";
}
@Override
public ClientHttpResponse fallbackResponse(Throwable cause) {
if (cause instanceof HystrixTimeoutException) {
return response(HttpStatus.GATEWAY_TIMEOUT);
} else {
return this.fallbackResponse();
}
}
@Override
public ClientHttpResponse fallbackResponse() {
return this.response(HttpStatus.INTERNAL_SERVER_ERROR);
}
private ClientHttpResponse response(final HttpStatus status) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return status;
}
@Override
public int getRawStatusCode() throws IOException {
return status.value();
}
@Override
public String getStatusText() throws IOException {
return status.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("服务不可用,请稍后再试。".getBytes());
}
@Override
public HttpHeaders getHeaders() {
// headers设定
HttpHeaders headers = new HttpHeaders();
MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
headers.setContentType(mt);
return headers;
}
};
}
}
添加回退方法后,重复上面实验,看看有什么效果。
异常:
也许可能只有我遇到,先粘贴上来,我遇到这个异常是一个很无脑的问题产生的,希望你不要碰到,如果碰到了跟我的类似存在疑惑,可咨询我。
2018-10-22 09:29:03.885 WARN 7232 --- [nio-8026-exec-4] o.s.c.n.z.filters.post.SendErrorFilter : Error during filtering
com.netflix.zuul.exception.ZuulException: Forwarding error
at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.handleException(RibbonRoutingFilter.java:189) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.forward(RibbonRoutingFilter.java:164) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.run(RibbonRoutingFilter.java:111) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112) ~[zuul-core-1.3.0.jar:1.3.0]
at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:193) ~[zuul-core-1.3.0.jar:1.3.0]
at com.netflix.zuul.FilterProcessor.runFilters(FilterProcessor.java:157) ~[zuul-core-1.3.0.jar:1.3.0]
at com.netflix.zuul.FilterProcessor.route(FilterProcessor.java:118) ~[zuul-core-1.3.0.jar:1.3.0]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
Caused by: com.netflix.client.ClientException: null
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:118) ~[ribbon-loadbalancer-2.2.4.jar:2.2.4]
at org.springframework.cloud.netflix.zuul.filters.route.support.AbstractRibbonCommand.run(AbstractRibbonCommand.java:117) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.cloud.netflix.zuul.filters.route.support.AbstractRibbonCommand.run(AbstractRibbonCommand.java:46) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:302) ~[hystrix-core-1.5.12.jar:1.5.12]
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:298) ~[hystrix-core-1.5.12.jar:1.5.12]
备注:
在Spring cloud Edgware版本之前,要想回退,需实现ZuulFallBackProvider接口,从Spring cloud Edgware版本之后,实现FallbackProvider接口。
1.gitee:https://gitee.com/StarskyBoy/cloud
2.github: https://github.com/StarskyBoy/cloud