框架 | 版本 |
---|---|
Spring Boot | 2.0.0.RELEASE |
Spring Cloud | Finchley.RELEASE |
Zuul | 1.3.1 |
JDK | 1.8.x |
参考上一篇:https://cloud.tencent.com/developer/article/1333841
基于源码:https://github.com/ken-io/springcloud-course/tree/master/chapter-07
启动Eureka Server: http://localhost:8800
启动Test Service:http://localhost:8602,http://localhost:8603
Zuul作为服务网关为了保证自己不被服务拖垮,本身已经集成了Hystrix对路由转发进行隔离。
为了方便开发人员对服务短路进行自定义处理,
Zuul 提供了 ZuulFallbackProvider 接口,开发人员可以通过实现该接口来完成自定义Hystrix Fallback
Spring Cloud Zuul 提供了 FallbackProvider替代了ZuulFallbackProvider接口。因此我们实现FallbackProvider即可
基于上一篇中zuul项目的源码进行修改即可:https://github.com/ken-io/springcloud-course/tree/master/chapter-07/zuul
在src\main\java\io\ken\springcloud\zuul创建package:provider
然后创建Filter类:ApiFallbackProvider.java
实现FallbackProvider并标记为@Component
package io.ken.springcloud.zuul.provider;
import com.netflix.hystrix.exception.HystrixTimeoutException;
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.util.logging.Logger;
@Component
public class ApiFallbackProvider implements FallbackProvider {
private Logger logger = Logger.getLogger(ApiFallbackProvider.class.toString());
@Override
public String getRoute() {
return "*";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
logger.warning(String.format("route:%s,exceptionType:%s,stackTrace:%s", route, cause.getClass().getName(), cause.getStackTrace()));
String message = "";
if (cause instanceof HystrixTimeoutException) {
message = "Timeout";
} else {
message = "Service exception";
}
return fallbackResponse(message);
}
public ClientHttpResponse fallbackResponse(String message) {
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 {
String bodyText = String.format("{\"code\": 999,\"message\": \"Service unavailable:%s\"}", message);
return new ByteArrayInputStream(bodyText.getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
项 | 说明 |
---|---|
getRoute() | 该Provider应用的Route ID,例如:testservice,如果设置为 * ,那就对所有路由生效 |
fallbackResponse(String route, Throwable cause) | 快速回退失败/响应,即处理异常并返回对应输出/响应内容。route:发生异常的RouteID,cause:触发快速回退/失败的异常/错误 |
ClientHttpResponse | Spring提供的HttpResponse接口。可以通过实现该接口自定义Http status、body、header |
启动zuul项目,访问 http://localhost:8888/testservice?token=123
会得到正常响应内容:
{
"code": 0,
"message": "hello",
"content": null,
"serviceName": "testservice",
"host": "localhost:8602"
}
关掉testservice启动的实例。然后再访问 http://localhost:8888/testservice?token=123 ,就会看到
{
"code": 999,
"message": "Service unavailable:Timeout"
}
上一节咱们提到了,Zuul本身就集成了Hystrix,实际上Zuul的路由转发也是用到了Ribbon+Hystrix,也就意味着我们可以通过Hystrix Dashboard监控Zuul的工作情况
新建package:configuration,然后在此package下创建HystrixConfiguration.java
package io.ken.springcloud.zuul.configuration;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HystrixConfiguration {
@Bean(name = "hystrixRegistrationBean")
public ServletRegistrationBean servletRegistrationBean() {
ServletRegistrationBean registration = new ServletRegistrationBean(
new HystrixMetricsStreamServlet(), "/hystrix.stream");
registration.setName("hystrixServlet");
registration.setLoadOnStartup(1);
return registration;
}
@Bean(name = "hystrixForTurbineRegistrationBean")
public ServletRegistrationBean servletTurbineRegistrationBean() {
ServletRegistrationBean registration = new ServletRegistrationBean(
new HystrixMetricsStreamServlet(), "/actuator/hystrix.stream");
registration.setName("hystrixForTurbineServlet");
registration.setLoadOnStartup(1);
return registration;
}
}
配置完成后重启启动zuul,访问 http://localhost:8888/hystrix.stream 或者
http://localhost:8888/actuator/hystrix.stream
就可以看到Hystrix流信息.(之所以配置两个入口,是为了满足turbine需要)
//截取片段
{"type":"HystrixCommand","name":"testservice","group":"RibbonCommand","currentTime":1532412948030,"isCircuitBreakerOpen":false,"errorPercentage":100,"errorCount":1,"requestCount":1}
这时候我们通过已有看板以链接方式查看Hystrix Dashboard,或者可以用Turbine来聚合Hystrix数据了。
当然,也可以在zuul项目中引入Hystrix Dashboard 进行监控。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
@EnableHystrixDashboard
注解package io.ken.springcloud.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableHystrixDashboard
@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
配置完成后重启启动zuul,访问 http://localhost:8888/hystrix ,就可以看到门户页
具体操作,不再赘述,参考本系列前面几篇Hystrix随笔即可
https://github.com/ken-io/springcloud-course/tree/master/chapter-08
https://cloud.tencent.com/developer/article/1333822
https://cloud.tencent.com/developer/article/1333825