Eureka用于服务的注册于发现,Feign支持服务的调用以及均衡负载,Hystrix处理服务的熔断防止故障扩散,Spring Cloud Config服务集群配置中心,那外部请求如何调用服务?如何进行路由和过滤?
在微服务架构中,后端服务往往不直接开放给调用端,而是通过一个API网关根据请求的url,路由到相应的服务。当添加API网关后,在第三方调用端和服务提供方之间就创建了一面墙,这面墙直接与调用方通信进行权限控制,后将请求均衡分发给后台服务端。
Spring Cloud Zuul路由是微服务架构的不可或缺的一部分,提供动态路由,监控,弹性,安全等的边缘服务。Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器。
Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。
一、Zuul基础功能:路由和过滤
1.创建eureka_zuul工程,pom.xml如下
4.0.0
com.kevin
euraka_zuul
0.0.1-SNAPSHOT
jar
euraka_zuul
http://maven.apache.org
UTF-8
org.springframework.boot
spring-boot-starter-parent
2.1.4.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-netflix-zuul
org.springframework.cloud
spring-cloud-dependencies
Greenwich.SR1
pom
import
2. application.properties定义路由地址
spring.application.name=eurekaZuul
server.port=9301
eureka.client.serviceUrl.defaultZone=http://localhost:9101/eureka/
zuul.routes.ribbon.path=/ribbon/**
zuul.routes.ribbon.serviceId=eurekaRibbon
zuul.routes.feign.path=/feign/**
zuul.routes.feign.serviceId=eurekaFeign
3. Application.java开启zuul代理
package com.kevin.euraka_zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class Application {
public static void main( String[] args ) {
SpringApplication.run(Application.class, args);
}
}
4. 如果需要进行过滤,可继承ZuulFilter。
Filter的生命周期有4个,分别是“PRE”、“ROUTING”、“POST”、“ERROR”;
TokenFilter.java:
package com.kevin.euraka_zuul.filter;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
@Component
public class TokenFilter extends ZuulFilter{
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
System.out.println(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
String accessToken = request.getParameter("token");
if(StringUtils.isEmpty(accessToken)) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(400);
ctx.setResponseBody("failed, no token");
}else {
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200);
}
return null;
}
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
}
二、熔断
1. 实现熔断类FallbackProvider,需要指定路由应用名和定义熔断返回内容
package com.kevin.euraka_zuul.filter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
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;
@Component
public class FeignFallback implements FallbackProvider{
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("The service is unavailable.".getBytes());
}
@Override
public String getStatusText() throws IOException {
return "OK";
}
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return 200;
}
@Override
public void close() {
}
};
}
@Override
public String getRoute() {
return "eurekaFeign";
}
}
2. 当eurekaFeign停止服务后,通过zuul访问,返回熔断信息
三、超时与重试
1. 可以通过以下配置设置超时时长
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000
ribbon.ConnectTimeout=3000
ribbon.ReadTimeout=6000
2. 重试
org.springframework.retry
spring-retry
配置文件:
#开启重试
zuul.retryable=true
#最大重试次数
client.ribbon.MaxAutoRetries=3
#切换相同Server的次数
client.ribbon.MaxAutoRetriesNextServer=0
参考:
https://cloud.spring.io/spring-cloud-static/Greenwich.SR1/single/spring-cloud.html#_router_and_filter_zuul
http://www.ityouknow.com/springcloud/2018/01/20/spring-cloud-zuul.html