1、spring-cloud-starter-netflix-zuul
的基本使用
1.1、 依赖y引入:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
1.2、激活方式
@EnableZuulProxy
@SpringBootApplication @EnableZuulProxy @EnableDiscoveryClient public class ZuulService {public static void main(String[] args) {SpringApplication.run(ZuulService.class, args);} }
1.3、配置路由:
Ⅰ、简化版配置方式:
zuul.routes.user-service=/userapi/**
配置说明:user-service:spring.application.name
/userapi/** :表示访问zuul服务的时候只要url中包含userapi的全部转发到user-service服务。
Ⅱ:复杂版本配置方式:
zuul:routes:route1:path: /userapi/**serviceId: user-serviceroute2:path: /orderapi/**serviceId: user-serviceroute3:path: /xxx/**url: http://localhost:8080/xxx-service //xxx-service为application的name
2、zuul自定义filter
2.1、 zuul是基于servlet的api网关,他允许我们自定义filter,但是这个filter 并非是Servlet 范畴的Filter,而是zuul范畴的Filter,自定义zuul范畴的Filter只要实现zuul提供的抽象类ZuulFilter即可:
案例如下:校验请求头中token:
public class TokenVerifyFilter extends ZuulFilter {@Overridepublic String filterType() {return "pre";} ?@Overridepublic int filterOrder() {return 0;} ?@Overridepublic boolean shouldFilter() {return true;} ?@Overridepublic Object run() throws ZuulException {RequestContext currentContext = RequestContext.getCurrentContext();HttpServletRequest request = currentContext.getRequest();String token = request.getHeader("token"); ?if (!StringUtils.isNotEmpty(token)){ ?/*通过context.setSendZuulResponse(false)可以终止请求的转发,但是只在pre类型的过滤器中设置才可以,原因是route 类型的filter 第一位就是RibbonRoutingFilter,这个filter就是用于向目标服务发起请求的,而在这个RibbonRoutingFilter的shouldFilter()里面,判断了只有currentContext的sendZuulResponse中为true才会执行RibbonRoutingFilter的run()方法去发起目标服务调用。*/ ?currentContext.setSendZuulResponse(false);currentContext.setResponseStatusCode(401);currentContext.setResponseBody("unAuthrized");}return "TokenVerifyFilter";} }
2.2、注册自定zuulFilter:
@Bean public TokenVerifyFilter tokenVerifyFilter(){return new TokenVerifyFilter(); }
2.3、 zuul中提供了默认的zuulFilter列表,关系如下:
3、在zuul api网关层进行服务容/降级
zuul提供了在api网关层进行服务容错/降级处理,我们只需要实现一个FallbackProvider接口,并注册自己的容错/降级实现即可:
案例如下:如果服务调用异常那就在响应body中写入"fallback"字符串。
/*** zuul 服务容错*/ @Component public class TestFallBbackProvider implements FallbackProvider { ?@Overridepublic String getRoute() {return "user-service"; //只对服务user-service进行Zuul网关的容错} ?@Overridepublic ClientHttpResponse fallbackResponse(String route, Throwable cause) {if (cause instanceof HystrixTimeoutException) {return response(HttpStatus.GATEWAY_TIMEOUT);} else {return response(HttpStatus.INTERNAL_SERVER_ERROR);}} ?private ClientHttpResponse response(final HttpStatus status) {return new ClientHttpResponse() {@Overridepublic HttpStatus getStatusCode() throws IOException {return status;} ?@Overridepublic int getRawStatusCode() throws IOException {return status.value();} ?@Overridepublic String getStatusText() throws IOException {return status.getReasonPhrase();} ?@Overridepublic void close() {} ?@Overridepublic InputStream getBody() throws IOException {return new ByteArrayInputStream("fallback".getBytes());} ?@Overridepublic HttpHeaders getHeaders() {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);return headers;}};} }
4、zuul限流
4.1、我们可以在zuul层进行限流处理,需要引入限流依赖,依赖如下:
<dependency><groupId>com.marcosbarbero.cloud</groupId><artifactId>spring-cloud-zuul-ratelimit</artifactId><version>1.3.4.RELEASE</version> </dependency>
4.2、统一配置所有服务的限流规则:
zuul.ratelimit.enabled=true : 开启zuul限流 #配置60秒内最多有两次请求 zuul.ratelimit.default-policy.limit=2 zuul.ratelimit.default-policy.refresh-interval=60 #针对url限流 zuul.ratelimit.default-policy.type=url ? ##针对IP进行限流,不影响其他IP,还可以设置为URL IP限流就是当前IP不管请求什么接口都会进行限流 ## URL限流则表示只是针对某个URL进行调用者限流,同一个调用者多个URL间限流是隔离开的。 ##zuul.ratelimit.default-policy.type=origin 表示IP限流 ##zuul.ratelimit.default-policy.type=url 表示URL限流
4.3、正对单个服务进行限流:
zuul.ratelimit.enabled=true : 开启zuul限流 #可以对单个服务进行限流,配置的方式如下 zuul.ratelimit.policies.user-service.limit=2 zuul.ratelimit.policies.user-service.refresh-interval=60 zuul.ratelimit.policies.user-service.type=url
5、zuul超时/重试控制:
默认zuul会结合ribbon、erueka、hystrix、openfeign来使用,因此控制超时时长也是需要调优一下:
# 当请求通过zuul网关路由到服务,并等待服务返回响应,这个过程中zuul也有超时控制。zuul的底层使用的是Hystrix+ribbon来实现请求路由。 # zuul中的Hystrix内部使用线程池隔离机制提供请求路由实现,其默认的超时时长为1000毫秒。ribbon底层默认超时时长为5000毫秒。 # 如果Hystrix超时,直接返回超时异常。如果ribbon超时,同时Hystrix未超时,ribbon会自动进行服务集群轮询重试,直到Hystrix超时为止。 # 如果Hystrix超时时长小于ribbon超时时长,ribbon不会进行服务集群轮询重试。因此我们会把hystrix的超时时间设置 > ribbon 超时时间。 zuul.retryable=true # hystrix 线程池隔离,默认超时时间1000ms hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=80000 # ribbon 连接超时时间 ribbon.ConnectTimeout=5000 # ribbon请求处理的超时时间: 默认5000ms ribbon.ReadTimeout=5000 # 重试次数:MaxAutoRetries表示访问服务集群下原节点(同路径访问),MaxAutoRetriesNextServer表示访问服务集群下其余节点(换台服务器) ribbon.MaxAutoRetries=1 ribbon.MaxAutoRetriesNextServer=1 # ribbon 开启重试 ribbon.OkToRetryOnAllOperations=true
除此之外还要结合openfeign的超时时间来进行控制:
#设置feign的请求超时时间为2秒 feign.client.config.default.read-timeout=5000
需要引入的依赖:
<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId> </dependency>
6、zuul动态路由:
zuul 结合spring-cloud-config 来进行路由的动态配置,当我们新加一个服务的时候,我们只需要修改spring-cloud-config-server上的zuul服务的配置,然后想办法属性路由配置即可,最简单的刷新方式就是开启zuul服务是actuator,暴露refresh端点,然后调用:localhost:6060/actuator/refresh即可刷新路由,整个过程不用重启zuul服务!!!!!!!!!!!!
步骤:
1、将config-server 注册到eureka 上。
2、zuul服务整合spring-cloud-config-client :
整合的配置:bootstrap.properties中:
spring.application.name=zuul-server server.port=6060 ? #配置zuul服务的配置文件名称 spring.cloud.config.name=zuul ? #开启配置服务从服务注册/发现的方式寻找 spring.cloud.config.discovery.enabled=true ? #配置配置服务的 服务名称 spring.cloud.config.discovery.service-id=config-server ? #配置eureka 地址 eureka.client.service-url.defaultZone=http://localhost:9090/eureka ? #以web暴露所有的actuator 端点 management.endpoints.web.exposure.include=*
3、修改config-server 上的zuul配置,例如添加路由。
4、不重启zuul服务刷新zuul配置,使用actuator/refresh 端点来进行手动刷新,此处可改造,改造的方式很多,可自行解决,例如定时任务也可以啊。
7、zuul的原理:
核心类:ZuulServlet : 标准的Setvlet规范。
各种实现的ZuulFilter