1 介绍
1.1 前言
在微服务框架中,每个对外服务都是独立部署的,对外的Api或者服务地址都不是不尽相同的。对于内部而言,通过注册中心自动感知即可。但大部分情况下,服务都是提供给外部系统进行调用的,不可能同享一个注册中心。同时一般上内部的微服务都是在内网的,和外界是不连通的。而且,就算每个微服务对外开放,对于调用者而言,调用不同的服务的地址或者参数也是不尽相同的,这样就会造成消费者客户端的复杂性,同时,可能微服务可能是不同的技术栈实现的,有的是Http、Rpc或者Websocket等等,也会进一步加大客户端的调用难度。所以,一般上都有会有个Api网关,根据请求的url不同,路由到不同的服务上去,同时入口统一了,还能进行统一的身份鉴权、日志记录、分流等操作。
1.2 什么是Zuul网关
微服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、均衡负载功能之外,它还具备了权限控制等功能。Zuul 是Zuul是Netflix开源的微服务网关,本质上是一个Web Servlet应用,可以和Eureka、Ribbon、Hystrix等组件配合使用,Spring Cloud对Zuul进行了整合与增强,和其他组件配合使用相对方便,Zuul的主要功能是路由转发和过滤器。
Zuul基于JVM的路由器和服务器端负载均衡器。同时,Zuul的规则引擎允许规则和过滤器基本上用任何JVM语言编写,内置支持Java和Groovy。这个功能,就可以实现动态路由的功能了。当需要添加某个新的对外服务时,一般上不停机更新是通过数据缓存配置或者使用Groovy进行动态路由的添加的。
1.3网关的意义
微服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、均衡负载功能之外,它还具备了权限控制等功能。
在未加入网关时,一般上会在服务外网架设一个负载均衡,如Nginx等。此时,微服务的组成如下图所示:
此时,对于Open Service而言可能需要提供权限控制等和业务无关的能力,这样本身就破坏了微服务服务单一的原则。所以,一般上在Open Service之上,还有一层服务提供诸如通用的权限校验、参数校验等功能,此服务就是网关了。之后,对于内部微服务而言,只需要关系各自微服务提供的业务功能即可,无需去关心其他非业务相关的功能。
Zuul做为路由网关,在微服务架构中有着十分重要的作用,体现在这几方面:
a. Zuul、Ribbon、Eureka结合,可以实现智能路由和负载均衡的功能,Zuul能够将请求流量按照某种策略分发到集群状态的多个服务实例;
b. 网关将所有服务的Api接口统一聚合,并统一对外暴露,外界系统调用Api接口时,都是由网关对外暴露的Api接口,外界系统不需要知道微服务系统中各服务相互调用的复杂性,保护了其微服务单元Api接口防止被外界直接调用,导致服务的敏感信息对外暴露;
c. 网关服务可以做到用户身份认证和权限认证,防止非法请求操作Api接口,对服务器起保护作用;
d. 网关可以流量监控、实时日志记录等功能;
加入Zuul网关后:
Zuul可以通过加载动态过滤机制,从而实现以下各项功能:
a.验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。
b.审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。
c.动态路由: 以动态方式根据需要将请求路由至不同后端集群处。
d.压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。
e.负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。
f.静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。
g.多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽可能接近。
1.4 网关的优缺点
优点:
a.减少Api请求次数
b.限流
c.缓存
d.统一认证
e.降低微服务的复杂度
f.支持混合通信协议(前端只和api通信,其他的由网关调用)
缺点:
a.网关需高可用,可能产生单点故障
b.管理复杂
2 Zuul的三大模块
目前网上大多数关于Zuul的相关讨论大都是 Spring-Cloud-Zuul相关的,但是笔者认为Spring Cloud Zuul 有利也有弊。好处就是开发起来比较方便,一个注解就可以启用一个网关,并且增加了一些默认的过滤器组件;但是Spring Cloud 为了开发者的快速接入,也对Netflix Zuul 的一些功能做了阉割。Netflix Zuul 主要包含了三大模块:Zuul核心模块、过滤器加载模块、过滤器管理模块。其中核心模块和过滤器加载模块,在Spring Cloud Zuul 的定制版本中,都没有做太大的改动。
2.1 核心模块
请求接收然后通过 pre、route、post 三个主要类型的过滤器。当然了,还有另外2 中上图中没有展现,就是 error 和 custom 类型的过滤器。error 是处理异常时的处理动作,custom 是自定义处理请求的过滤流程。上面各个过滤器之间是通过 RequestContext (Map类型,ThreadLocal 变量) 来做上下文传递的。ZuulFilterRunner 组织了各种类型的过滤器的执行逻辑。
2.2.1 ZuulServlet
ZuulServlet 依次执行了 pre过滤器、route过滤器、post过滤器;当产生错误时,会执行error 过滤器。以上各种类型的 Filter 会委派给ZuulRunner 去执行。
2.2.2 ZuulRunner
ZuulRunner 本身也没什么逻辑,而是使用了单例的处理器 FilterProcessor 来处理。
2.2.3FilterProcessor
FilterProcessor 回去从 FilterLoader 中获取各个类型的过滤器,并且顺序执行。
2.2.4 RequestContext
各个 Filter 执行的过程中不能直接相互通信,参数的传递依赖是通过 线程本地变量 RequestContext 来实现的。
2.2.4 ZuulFilter
Zuul提供了动态读取、编译和执行Filter的框架。各个Filter间没有直接联系,但是都通过RequestContext共享一些状态数据。尽管Zuul支持任何基于JVM的语言,但是过滤器目前是用Groovy编写的。 每个过滤器的源代码被写入到Zuul服务器上的一组指定的目录中,这些目录将被定期轮询检查是否更新。Zuul会读取已更新的过滤器,动态编译到正在运行的服务器中,并后续请求中调用。
关键特性:
· Type:用以表示路由过程中的阶段(内置包含PRE、ROUTING、POST和ERROR)
· Execution Order:表示相同Type的Filter的执行顺序
· Criteria:执行条件
· Action:执行体
请求生命周期:
Zuul 大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。
· PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
· ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用 Apache HttpClient 或 Netfilx Ribbon 请求微服务。
· POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
· ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul 还允许我们创建自定义的过滤器类型。例如,我们可以定制一种 STATIC 类型的过滤器,直接在 Zuul 中生成响应,而不将请求转发到后端的微服务。
Zuul 中默认实现的 Filter
类型 | 顺序 | 过滤器 | 功能 |
---|---|---|---|
pre | -3 | ServletDetectionFilter | 标记处理 Servlet 的类型 |
pre | -2 | Servlet30WrapperFilter | 包装 HttpServletRequest 请求 |
pre | -1 | FormBodyWrapperFilter | 包装请求体 |
pre | 1 | DebugFilter | 标记调试标志 |
pre | 5 | PreDecorationFilter | 处理请求上下文供后续使用 |
route | 10 | RibbonRoutingFilter | serviceId 请求转发 |
route | 100 | SimpleHostRoutingFilter | url 请求转发 |
route | 500 | SendForwardFilter | forward 请求转发 |
post | 0 | SendErrorFilter | 处理有错误的请求响应 |
post | 1000 | SendResponseFilter | 处理正常的请求响应 |
2.2 过滤器加载模块
过滤器加载模块主要是给Core 模块的FilterRunner 提供服务的,也就是提供编译好的Filter组件。其中的FilterFileManager 是以轮询的方式,不断的从包含groovy 脚本的目录中加载文件,提供给 FilterLoader 编译和管理。
具体流程:
过滤器加载模块主要提供给 Core 模块,从磁盘(或者网络等其他介质)中加载Filter ,并完成实例化的过程,以备Core 模块的使用。其中FilterFileManager 负责从磁盘中加载数据,然后调用FilterLoader 的单例,去实例化Filter以备用。FilterFileManager会启用一个守护线程,在后台不断地循环管理Filter 文件(源码中每次循环后,会休息1秒钟)。循环每个Filter 都会调用 FilterLoader.getInstance().putFilter() 将其放入FilterLoader的Map中。
2.3 过滤器管理模块
过滤器管理模块对于运维和做一些功能增强时非常有帮助,大多数情况下都需要对其做定制开发,从而适应各个公司不同的业务需求。上面的过滤器加载模块最终交互的对象是磁盘文件,那么过滤器管理模块就相对是个独立的东西了。相关的操作就是Filter 文件。
具体流程:
过滤器管理模块直接操作文件的类是:ZuulFilterPoller 。它会起一个线程,不断的循环去抓取Filter的元数据(源码中由ZuulFilterDAO提供)。官方给的默认的实现是 Cassandra,也就是Filter的元数据是从 Cassandra 数据库中获取的。但是这个数据库在国内用的相对较少,如果要定制的话,通常会改成 MySQL 或者 Http接口的方式去实现。ZuulFilterPoller 中起了一个循环线程,不断的去获取元数据的信息,从而更新Filter。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/71427.html