SpringCloud-5-Netflix-5-Zuul

简介: spring cloud中的微服务网关,Spring Cloud Netflix下的路由器和过滤器:Zuul。

今天看spring cloud中的微服务网关,Spring Cloud Netflix下的路由器和过滤器:Zuul。

网关是什么?

       网关是一个网络整体系统中的门户、入口。请求应该先请求网关微服务,通过网关微服务进行路径的路由,再定位到具体的服务节点上。

       网关可以实现网络整体系统内部与外部的隔离,增强后端系统的安全性,不过没有网关我们也可以正常访问服务节点,那么说明网关并不是必须依赖的哈。

       那么Zuul可以做什么呢?

       一系列的过滤器。。。去看看源码,看来玩的就是这些实现类啦!

       说起网关第一想到的肯定是路由地址和请求拦截。

       上图所示,我们在client中发布了两个节点,下面试试新建一个网关zuul项目,访问zuul直接路由到client。

一、路由

1.建立StudyCloud-eureka-zuul子项目,既然实现网关与节点的交互,那肯定也是要注册到Eureka注册中心的。

<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.xing</groupId><artifactId>StudyCloud</artifactId><version>0.0.1-SNAPSHOT</version></parent><artifactId>StudyCloud-eureka-zuul</artifactId><version>0.0.1-SNAPSHOT</version><dependencies><!--web组件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--eureka客户端--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency><!--Zuul限流保护--><dependency><groupId>com.marcosbarbero.cloud</groupId><artifactId>spring-cloud-zuul-ratelimit</artifactId><version>1.3.4.RELEASE</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

2.配置和client一样,注册到注册中心哈

spring.application.name=zuulserver.port=8883eureka.instance.instance-id=zuuleureka.client.service-url.defaultZone=http://172.23.13.15:8881/eureka/

3.使用@EnableZuulProxy注解开启zuul的api网关服务功能

packagecom.xing.study.cloud.zuul;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.netflix.eureka.EnableEurekaClient;
importorg.springframework.cloud.netflix.zuul.EnableZuulProxy;
/*** @author xh*/@SpringBootApplication@EnableEurekaClient@EnableZuulProxypublicclassZuulApplication {
publicstaticvoidmain(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
    }
}

4.启动Eureka Server、client、Zuul三个项目

       查看Server可以看到都注册上去了。网关怎么访问呢?默认的zuul结合eureka会将注册到eureka的服务名作为访问的ContextPath。也就是说,通过zuul访问服务的,URL地址默认格式为:

http://zuulHostIp:port/要访问的服务名称/服务中的URL

       服务名称:properties配置文件中的spring.application.name。

       服务的URL:就是对应的服务对外提供的URL路径监听。

       当然,我们还可以通过配置来自定义一些东西,比如我觉得eureka-client1有点长,我给他在application.properties中配置成client:

##自定义服务的应用路由eureka-client1换成client1zuul.routes.eureka-client1=/client1/**

       把eureka-client1换成client1也能访问到了。

       也可以指定一些路由机制,用于覆盖默认约定的规则:

##url用于配置符合path的请求路径路由到的服务地址。#zuul.routes.eureka-client1.url=http://127.0.0.1:8082/##path用于配置路径匹配规则。#可使用的通配符有:***??-单个字符*-任意多个字符,不包含多级路径**-任意多个字符,包含多级路径#zuul.routes.eureka-client1.path=/api/**## serviceId用于配置符合path的请求路径路由到的服务名称。#zuul.routes.eureka-client1.serviceId=eureka-application-service# 配置不被zuul管理的服务列表。多个服务名称使用逗号','分隔。#zuul.ignored-services=eureka-client1,zuul# 通配方式配置排除网关代理路径。所有符合ignored-patterns的请求路径都不被zuul网关代理。#zuul.ignored-patterns=/**/test/**# 通配符*配置排除列表相当于给所有新发现的服务默认排除zuul网关访问方式,只有配置了路由网关的服务才可以通过zuul网关访问#zuul.ignored-services=*# prefix URL pattern 前缀路由匹配# 配置请求路径前缀,所有基于此前缀的请求都由zuul网关提供代理。#zuul.prefix=/api

二、Zuul中的服务降级处理

       zuul网关其底层使用ribbon来实现请求的路由,并内置Hystrix。点开pom依赖,可以看到zuul内置了熔断器hystrix来容错。

图片

1.实现FallbackProvider接口来提供网关fallback逻辑。

packagecom.xing.study.cloud.zuul;
importorg.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
importorg.springframework.http.HttpHeaders;
importorg.springframework.http.HttpStatus;
importorg.springframework.http.MediaType;
importorg.springframework.http.client.ClientHttpResponse;
importorg.springframework.stereotype.Component;
importjava.io.ByteArrayInputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.nio.charset.StandardCharsets;
/***  zuul的服务降级处理*  Zuul的fallback容错处理逻辑,只针对timeout异常处理,当请求被Zuul路由后,只要服务有返回(包括异常),都不会触发Zuul的fallback容错逻辑。*  因为对于Zuul网关来说,做请求路由分发的时候,结果由远程服务运算的。那么远程服务反馈了异常信息,Zuul网关不会处理异常,因为不确定异常是不是故意要返的* @author xh*/@ComponentpublicclassMyZuulFallbackProviderimplementsFallbackProvider {
/*** return - 返回fallback处理哪一个服务。返回的是服务的名称*/@OverridepublicStringgetRoute() {
return"eureka-client1";
    }
@OverridepublicClientHttpResponsefallbackResponse(Stringroute, Throwablecause) {
returnnewClientHttpResponse() {
/*** 设置响应的头信息*/@OverridepublicHttpHeadersgetHeaders() {
HttpHeadersheader=newHttpHeaders();
MediaTypemt=newMediaType("application", "json", StandardCharsets.UTF_8);
header.setContentType(mt);
returnheader;
            }
/*** 设置响应体* zuul会将本方法返回的输入流数据读取,并通过HttpServletResponse的输出流输出到客户端。*/@OverridepublicInputStreamgetBody() throwsIOException {
Stringcontent="失败";
returnnewByteArrayInputStream(content.getBytes());
            }
/*** ClientHttpResponse的fallback的状态码 返回String*/@OverridepublicStringgetStatusText() throwsIOException {
returnthis.getStatusCode().getReasonPhrase();
            }
/*** ClientHttpResponse的fallback的状态码 返回HttpStatus*/@OverridepublicHttpStatusgetStatusCode() throwsIOException {
returnHttpStatus.OK;
            }
/*** ClientHttpResponse的fallback的状态码 返回int*/@OverridepublicintgetRawStatusCode() throwsIOException {
returnthis.getStatusCode().value();
            }
/*** 回收资源方法* 用于回收当前fallback逻辑开启的资源对象的。* 不要关闭getBody方法返回的那个输入流对象。*/@Overridepublicvoidclose() {}
        };
    }
}

       网上搜了一个直接生成ClientHttpResponse。

2.关掉client服务,模拟节点宕机,测试异常是否会走fallback方法。

e2a3f3b3081a80d8ced6fdcf77d3e233.png

       成功返回了我们定义的失败信息。

三、以上都是使用的源码提供的过滤器哈,我们也可以自定义一个过滤器。

packagecom.xing.study.cloud.zuul;
importcom.netflix.zuul.ZuulFilter;
importcom.netflix.zuul.context.RequestContext;
importcom.netflix.zuul.exception.ZuulException;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springframework.stereotype.Component;
importjavax.servlet.http.HttpServletRequest;
/***  我的过滤器* @author rt*/@ComponentpublicclassMyZuulFilterextendsZuulFilter {
privatestaticfinalLoggerlog=LoggerFactory.getLogger(MyZuulFilter.class);
/*** 方法返回字符串数据,代表当前过滤器的类型。可选值有-pre, route, post, error。*      pre - 前置过滤器,在请求被路由前执行,通常用于处理身份认证,日志记录等;*      route - 在路由执行后,服务调用前被调用;*      error - 任意一个filter发生异常的时候执行或远程服务调用没有反馈的时候执行(超时),通常用于处理异常;*      post - 在route或error执行后被调用,一般用于收集服务信息,统计服务性能指标等,也可以对response结果做特殊处理。* @return pre, route, post, error。*/@OverridepublicStringfilterType() {
return"pre";
    }
/*** 用于为同filterType的多个过滤器定制执行顺序,返回值越小,执行顺序越优先。* @return 返回int数据*/@OverridepublicintfilterOrder() {
return0;
    }
/***  代表当前filter是否生效。*  默认值为false。返回true代表开启filter。* @return boolean*/@OverridepublicbooleanshouldFilter() {
returntrue;
    }
/*** 具体的过滤执行逻辑。*  如pre类型的过滤器,可以通过对请求的验证来决定是否将请求路由到服务上;*  如post类型的过滤器,可以对服务响应结果做加工处理(如为每个响应增加footer数据)。* @return obj* @throws ZuulException e*/@OverridepublicObjectrun() throwsZuulException {
try {
// 通过zuul,获取请求上下文RequestContextrc=RequestContext.getCurrentContext();
HttpServletRequestrequest=rc.getRequest();
log.info("MyZuulFilter.....method={},url={}",request.getMethod(),request.getRequestURL().toString());
ObjectaccessToken=request.getParameter("token");
if(accessToken==null){
log.warn("access token is empty");
//令zuul过滤该请求,不对其进行路由rc.setSendZuulResponse(false);
//设置返回的错误码rc.setResponseStatusCode(403);
            }
log.info("token ok 鉴权完毕, 记录日志完毕,统计性能");
        }catch (Exceptione){
log.error("发生异常",e);
        }
returnnull;
    }
}

      直接看没有传入token的结果:

badc610f9dc03b509f4371658b79907b.png

       这里也就是官网说的可以在这搞鉴权校验,识别每个请求的权限,拒绝不符合要求的请求。

四、Zuul网关的限流保护

       减载 - 为每种类型的请求分配容量并丢弃超出限制的请求。这个可以用ratelimit来实现:

1.pom

<!--Zuul限流保护--><dependency><groupId>com.marcosbarbero.cloud</groupId><artifactId>spring-cloud-zuul-ratelimit</artifactId><version>1.3.4.RELEASE</version></dependency>

2.application.properties

#开启限流保护zuul.ratelimit.enabled=true#针对IP进行限流,不影响其他IPip-ORIGIN,url-URLzuul.ratelimit.default-policy.type=origin#全局限流配置#60s内请求超过3次,服务端就抛出异常,60s后可以恢复正常请求zuul.ratelimit.default-policy.limit=3zuul.ratelimit.default-policy.refresh-interval=60#局部限流配置#eureka-client1服务60s内请求超过3次,服务抛出异常。zuul.ratelimit.policies.eureka-client1.limit=3zuul.ratelimit.policies.eureka-client1.refresh-interval=60

3.同一IP在60秒内访问第3次的时候就会报错,等60秒就可以继续访问啦。

1c29aa09e2c65a5b6581984fd0ddad7d.png

总结:

       Zuul作为一个微服务网关,由一系列的过滤器构成,可以使用提供的过滤器来实现路由分发、服务降级、限流等功能,也可以自定义拦截器来实现鉴权、日志等功能。底层使用ribbon来实现请求的路由,并内置Hystrix,可选择性提供网关fallback逻辑。

END

目录
相关文章
|
7月前
|
负载均衡 监控 算法
SpringCloud Netflix-springcloudnetflix(二)
SpringCloud Netflix-springcloudnetflix
65 3
|
7月前
|
Java API 微服务
SpringCloud Netflix-springcloudnetflix(四)
SpringCloud Netflix-springcloudnetflix
72 1
|
7月前
|
Dubbo Java 应用服务中间件
SpringCloud Netflix-springcloudnetflix(一)
SpringCloud Netflix-springcloudnetflix
80 1
|
7月前
|
运维 监控 Java
SpringCloud Netflix-springcloudnetflix(三)
SpringCloud Netflix-springcloudnetflix
73 1
|
7月前
|
消息中间件 Java 中间件
SpringCloud Netflix-springcloudnetflix(五)
SpringCloud Netflix-springcloudnetflix
72 1
|
负载均衡 算法 Java
springcloud netflix ribbon 使用
springcloud netflix ribbon 使用
137 0
|
负载均衡 Java Linux
springCloud搭建、zuul、feign、hystrix、ribbon(内部培训)
springCloud搭建、zuul、feign、hystrix、ribbon(内部培训)
176 0
springCloud搭建、zuul、feign、hystrix、ribbon(内部培训)
|
缓存 负载均衡 监控
Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul
Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul
1342 0
|
JSON 监控 安全
SpringCloud极简入门-服务网关-spring cloud zuul
为什么要zuul 试想一下如果我们有很多的微服务,他们都需要登录之后才能访问,那么我需要在每个微服务都去做一套登录检查逻辑,这样是不是会存在大量重复的代码和工作量,我们希望的是把登录检查这种公共的逻辑进行统一的抽取,只需要做一套检查逻辑即可,而zuul就可以用来干这类事情,我们可以把zuul看做是微服务的大门,所有的请求都需要通过zuul将请求分发到其他微服务,根据这一特性我们就可以在zuul做统一的登录检查,下游的微服务不再处理登录检查逻辑。
182 0
|
负载均衡 网络协议 算法
03、SpringCloud之Ribbon(netflix)学习笔记(一)
03、SpringCloud之Ribbon(netflix)学习笔记(一)
03、SpringCloud之Ribbon(netflix)学习笔记(一)