SpringCloud之服务15网关Zuul了解一下

文章资讯 2020-06-14 20:58:01

SpringCloud之服务15网关Zuul了解一下

一、为什么需要网管
1、不同的微服务一般会有不同的网络地址,外部客户端可能需要调用多个服务的接口才能完成一个业务需求。电商完成一条购物流程
a:流程图httquesthttquesthttquesthttquesthttquestCent查寻商品分类服务查询商品库存服务订单服务支付系统服务其他服务没有网关存在问题a:客户端会多次请求不同的微服务,增加了客户端的复杂性。
b:存在跨域请求,在一定场景下处理相对复杂。
c:认证复杂,每个服务都需要独立认证。
d:难以重构,随着项目的迭代,可能需要重新划分微服务。例如:将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施,这样可能比重写一个都麻烦。
e:微服务可能使用了防火墙浏览器不友好的协议,直接访问会有一定的困难。解决方案a:流程图httquestaentquestaentquestaentquestaentquestaentquestCent服务网关查寻商品分类服务查询商品库存服务订单服务支付系统服务其他服务
优点a:解决耦合,减少了客户端与各个微服务之间的交互次数。
b:易于监控,可在微服务网关收集监控数据并将其推送到外部系统进行分析。
c:易于认证。可在微服务网关上进行认证,然后再将请求转发到后端的微服务,无须在每个微服务中进行认证。二、Zuul网关
1、Zuul是Netfx开源的一个API网关,本质上是一个WebServlet应用。Zuul也是SrinCloud全家桶中的一员,它可以和Euka(注册中心)、Ribbon(负载均衡)、Hystrix(限流)等组件配合使用。
2、代码托管地址
3、核心功能过滤器
验证与安全保障:识别面向各类资源的验证要求并拒绝与要求不符的请求。
审查与监控:在边缘位置追踪有意义数据及统计结果,从而带来准确的生产状态结论。
动态路由:以动态方式根据需要将请求路由至不同后端集群处。
压力测试:逐渐增加指向集群的负载流量,从而计算性能水平。
负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。
静态响应处理:在边缘位置直接建立部分响应,从而避免其流入内部集群。
注:以上介绍来自Zuul官方文档,但其实开源版本的Zuul以上功能一个都没有——开源的Zuul只是几个Jar包而已,以上能力指的应该是Netfx官方自用的Zuul的能力。
4、小试牛刀
基于Srinboot搭建oodsserver、ordersserver
依赖
<deendencies&t;
<deendency&t;
<rouId&t;or.srinframework.cloud<rouId&t;
<artifactId&t;srin-cloud-starter-netfx-zuul<artifactId&t;
<version&t;2.2.2.RELEASE<version&t;
<deendency&t;
<deendency&t;
<rouId&t;or.srinframework.cloud<rouId&t;
<artifactId&t;srin-cloud-starter-netfx-euka-cent<artifactId&t;
<version&t;2.2.2.RELEASE<version&t;
<deendency&t;
<deendencies&t;
配置文件acation.yml
srin:
acation:
name:zuul-serviceeuka:
cent:
service-url:
defaultZone:htt:localhost:8761eukaserver:
ort:6069启动imortor.srinframework.boot.SrinAcation;
imortor.srinframework.boot.autoconfiu.SrinBootAcation;
imortor.srinframework.cloud.netfx.zuul.EnableZuulProxy;@SrinBootAcation
@EnableZuulProxy
ubcclassZuulServiceAcation{
ubcstaticvoidmain(Strin[]ars){
SrinAcation.run(ZuulServiceAcation.class,ars);
}
}启动Euka、Zuul、启动两个服务oodsserver、ordersserver
访问htt:localhost:8081orders-serveroods
htt:localhost:8082oods-serverorders5、ZuulFilter接口
filterTye:过滤器的类型(Tye)它决定过滤器在请求的哪个生命周期中执行。
filterOrder:过滤器的执行顺序(ExecutionOrder)当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行。
shouldFilter:判断该过滤器是否需要被执行(Criteria)这里我们直接返回了true,因此该过滤器对所有的请求都生效。生产环境根据需求+函数判断。
run:过滤器的具体执行逻辑(Action)
6、ZuulFilter代码实现ackaecom.haoxianshen.srincloud.filter;imortcom.netfx.zuul.ZuulFilter;
imortcom.netfx.zuul.context.RequestContext;
imortcom.netfx.zuul.excetion.ZuulExcetion;
imortor.slf4j.Loer;
imortor.slf4j.LoerFactory;
imortor.srinframework.steotye.Comonent;imortjavax.servlet.htt.HttServletRequest;
imortjava.io.IOExcetion;
imortjava.util.Objects;**
*@authorhaoxianshen
*
@Comonent
ubcclassLoinFilterextendsZuulFilter{
Loerloer=LoerFactory.etLoer(etClass());**
*请求路由前调用
*@turn
*
@Override
ubcStrinfilterTye(){
turn"";
}**
*int值来定义过滤器的执行顺序,数值越小优先级越高
*@turn
*
@Override
ubcintfilterOrder(){
turn0;
}**
*该过滤器是否执行,true执行false不执行
*@turn
*
@Override
ubcboeanshouldFilter(){
turntrue;
}
**
*业务逻辑
*@turn
*@throwsZuulExcetion
*
@Override
ubcObjectrun()throwsZuulExcetion{
RequestContextcontext=RequestContext.etCurntContext();
HttServletRequestquest=context.etRequest();
获取请求参数token的值
Strintoken=quest.etParameter("token");
if(Objects.isNull(token)){
loer.warn("此操作需要先登录系统。。。");
context.setSendZuulResonse(false);
context.setResonseStatusCode(200);
try{
响应结果
context.etResonse().etWriter().write("tokenisemty");}catch(IOExcetione){
e.rintStackTrace();
}
turnnull;
}
loer.info("ok");
turnnull;
}
}7、启动再次测试不正确的访问
htt:localhost:8082oods-serverorders
响应401
正确访问
htt:localhost:8082oods-serverorders?accessToken=flame
响应成功8、Filter的生命周期
httquesterrorquestrocessinturndatadatarocessinerrorhttsonseCentfiltersroutinfiltersostfiltersdoma
CentHTTP请求到达API网关服务。进入第一个阶段,主要做的事情是在进行请求路由之前做一些前置处理,比如权限限制等。
过滤器完成,进入第二个阶段routin(路由请求转发阶段),请求被routin类型的过滤器处理。转发到具体服务实例上,返回请求结果。
routin阶段完成,到达第三阶段ost,对返回解惑或者结合请求对返回做一些加工处理,返回Cent。
真正处理业务逻辑在run()方法中。
9、Zuul1.x架构图
Zuul的过滤器基本上是由Groovy语言编写的,这些过滤器起初以文件(以.roovy结尾)的形式存放在特定的目录下面。
FilterFileManaer职责:a:定期轮训存放Filter目录
b:新加入的或者修改过的过滤器会被动态的加载进来。
c:读取完的.roovy文件,会使用GroovyComer将其编译成为JVMClass,之后再实例化(Class.newInstance)成ZuulFilter对象(即过滤器),最终保存在FilterReistry中。FilterReistry可以看成是一个ConcurntHashMa,key:.roovy文件的路径,value:动态加载之后的ZuulFilter对象。
Zuul的过滤器之间没有直接的相互通信,通过一个RequestContext(也可以看成是一个ConcurntHashMa)来进行数据传递的。RequestContext类中由ThadLocal变量来记录每个Request所需要传递的数据。
请求进入Zuul,交由ZuulServlet处理,ZuulServlet中有一个ZuulRunner对象,该对象中初始化了前面所说的RequestContext。ZuulRunner中有一个FilterProcessor,FilterProcessor从FilterLoader(FilterReistry)中获取ZuulFilter(s)。
quwstiveiveetZuulFiltersFilterFileManaerloadCentZuulZuulServletZuulRunnerObjectFilterProcessorFilterLoaderFilterReistryfilters
ZuulServlet先执行的类型的过滤器,再执行route类型的过滤器,最后执行的是ost类型的过滤器,在执行这些过滤器有错误的时候则会执行error类型的过滤器。执行完这些过滤器,最终将请求的结果返回给客户端。
ZuulServletPFilterRoutinPostFterCent
三、Zuul2
1、Zuul2的三种类型
InboundFilters:在路由之前执行
EndointFilters:路由操作
OutboundFilters:得到相应数据之后执行
四、Zuul1vsZuul2
1、过滤器前端用NettyServer代替了原本Zuul1中的Servlet。
2、后端过滤器使用NettyCent代替了HttCent。
3、Zuul2在功能上也丰富和优化了很多如:HTTP2、WebSocket的支持。
4、Zuul2采用异步非阻塞模式特点:启动的线程很少,使用的线程资源少,上下文切换开销也少,非阻塞模式可以接受的连接数大大增加,复杂度也增加。5、Zuul1采用同步阻塞模式特点:
a:模型比较简单,请求-&t;处理-&t;响应的流程(callflow)都是在一个线程中处理的,开发调试也便于理解,Debu也比较方便。
b:同步阻塞模式一般会启动很多的线程,必然引入线程切换开销。同步阻塞模式下,容器线程池的数量一般是固定的,造成对连接数有一定限制。
c:当后台服务慢,容器线程池易被耗尽。一旦耗尽容器会拒绝新的请求,这个时候容器线程其实并不忙,只是被后台服务调用IO阻塞,资源浪费。五、Zuul1、Zuul2、SrinCloudGateway、Kon
1、根据特定场景选择合适的。性能、并发、个人技术实力(处理实际问题能力)2、异步相对来说业务比较复杂。