万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

Spring Cloud Gateway

Spring Cloud 2.x 实 现 了 社 区 生 态 下 的 Spring CloudGateway(简称SCG)微服务网关项目。Spring Cloud Gateway基于WebFlux框架开发,目标是替换掉Zuul。

Spring Cloud Gateway概述

Spring Cloud Gateway主要有两个特性:

①非阻塞,默认使用RxNetty作为响应式Web容器,通过非阻塞方式,利用较少的线程和资源来处理高并发请求,并提升服务资源利用的可伸缩性。

②函数式编程端点,通过使用Spring WebFlux的函数式编程模式定义路由端点,处理请求。

Spring Cloud Gateway可与Eureka、Ribbon、Hystrix等组件配合使用,基于Spring 5的Reactor和Spring Boot 2构建,使用Netty作为底层通信框架,支持异步非阻塞编程模型和响应式编程框架,解决了Zuul框架的I/O阻塞问题和线程收敛问题。使用Spring WebFlux框架可以使Spring Cloud Gateway在高并发场景下具有更好的性能表现,占用更少的资源。

下面是Spring Cloud官方对Spring Cloud Gateway特征的介绍。

● 基于Spring Framework 5、Reactor和Spring Boot 2.0框架。

● 根据请求的属性可以匹配对应的路由。

● 集成Hystrix。

● 集成Spring Cloud DiscoveryClient。

● 把易于编写的Predicates和Filters作用于特定路由。

● 具备一些网关的高级功能,如动态路由、限流、路径重写。

对于微服务网关来说,最核心的特征包括路由和过滤器机制。从功能特性上来看,Spring Cloud Gateway和Zuul具备相似的特性。它们都可以集成Hystrix、Ribbon负载均衡及Spring Cloud的现有组件来实现附加功能。而且Spring Cloud Gateway的本质特性还体现在底层的通信框架上,它可以基于Netty的I/O多路复用和事件响应机制来实现网络通信;它的另外一大特性就是使用Spring Framework 5的响应式编程模型,允许通过Spring WebFlux实现异步非阻塞特性,在性能和资源利用率上,都有了质的提升。在编程范式上,Spring CloudGateway使用函数式编程模式。官方提供的Spring Cloud Gateway的架构图如下所示。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

Spring Cloud Gateway的核心概念

简单说明一下架构图中的三个术语。

● Filter(过滤器):和Zuul的过滤器在概念上类似,可以使用Filter拦截和修改请求,实现对上游的响应,进行二次处理,实现横切与应用无关的功能,如安全、访问超时设置、限流等功能。

● Route(路由):网关配置的基本组成模块,和Zuul的路由配置模块类似。一个Route模块由一个ID、一个目标URI、一组断言和一组过滤器组成。如果断言为真,则路由匹配,目标URI会被访问。

● Predicate(断言):Predicate来自Java 8的接口,它可以用来匹配来自HTTP请求的任何内容,例如headers或参数。接口包含多种默认方法,并将Predicate组合成复杂的逻辑(与、或、非),可以用于接口参数校验、路由转发判断等。

Spring Cloud Gateway的接入和配置

Spring Cloud Gateway依赖Spring WebFlux提供的Netty运行时环境,所以Spring Boot必须是2.0或者以上版本。基本的Spring Cloud环境配置确认后,主要的接入步骤如下。

1.Maven依赖引入

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

2.路由配置方式一:配置文件方式

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

各字段含义如下。

● id:自定义的路由ID,保持唯一。

● uri:目标服务地址。

● predicates:路由条件,Predicate接受一个输入参数,返回一个布尔值结果。

○ 第一个Predicate基于URL的方式。配置文件的第一个路由的配置采用URL方式,配置了一个ID为url-proxy-1的URI代 理 规 则 。 路 由 的 规 则 为 : 当 访 问 地 址 为http://localhost:8080/csdn/1.jsp时,会路由到上游地址https://localhost:8010/1.jsp。○ 第二个Predicate基于服务ID发现的方式。配置文件的第二个路由的配置采用与注册中心相结合的服务发现方式,与单个URI的路由配置相比,区别其实很小,仅在于URI的schema协议不同。单个URI地址的schema协议,一般为HTTP或者HTTPs协议。

3.基于代码DSL方式的路由配置接入

路由转发功能同样可以通过代码来实现,我们可以在启动类GatewayApplication中添加customRouteLocator方法来定制转发规则,代码如下:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

Spring Cloud Gateway的工作原理

客户端向Spring Cloud Gateway发出HTTP请求后,如果GatewayHandlerMapping 确 定 请 求 与 路 由 匹 配 , 则 将 其 发 送 到 GatewayWebHandler。WebHandler通过该请求的特定过滤器链处理请求。过滤器 可 以 在 发 送 代 理 请 求 之 前 或 之 后 执 行 逻 辑 。 在 Spring CloudGateway的执行流程中,首先执行所有“pre filter”逻辑,然后进行回源请求代理。在请求代理执行完后,执行“post filter”逻辑。在“pre”类型的过滤器中,可以实现参数校验、权限校验、流量监控、日志输出、协议转换等功能;在“post”类型的过滤器中,可以实现响应内容、响应头的修改,日志的输出、流量监控等功能。核心工作流程如下图所示。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

Predicate条件

在Spring Cloud Gateway中,Spring利用Predicate的特性实现了各种路由匹配规则,通过Header、请求参数等不同条件来匹配对应的路由。

我们来看Spring Cloud Gateway内置的几种Predicate的使用方法。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

在上述配置文件中,如果多种Predicates同时存在于同一个路由,请求必须同时满足所有条件才能被这个路由匹配。当一个请求满足多个路由的Predicate条件时,请求只会被首个成功匹配的路由转发。下面分别对不同规则的路由匹配进行解释。

● 通过请求路径匹配(Path Route Predicate)

路由断言工厂接收一个参数,根据Path定义好的规则来判断访问的URI是否匹配。配置示例如下:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

如果请求路径符合要求,则此路由将匹配,例如/hello/1或者/hello/world。

使用curl测试,命令行输入:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

经过测试发现,第一条和第二条命令可以正常获取页面返回值,最后一个命令报404错误,证明路由是通过指定路径来匹配的。

● 通过请求参数匹配(Query Route Predicate)

路由断言工厂接收两个参数:一个必需的参数和一个可选的正则表达式。配置示例如下:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

在这样的配置中,只要请求中包含helloworld属性的参数即可匹配路由。使用curl测试,命令行输入:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

经过测试发现,只要请求中带有helloworld参数就会匹配路由,不带helloworld参数则不会匹配。还可以将Query的值以键值对的方式进行配置,这样在请求时会对属性值和正则表达式都进行匹配,键值对匹配后才会正确执行路由逻辑。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

在上述路由匹配中,请求中包含hello属性并且参数值是以world开头的、长度为三位的字符串,才会进行匹配和路由。使用curl测试,命令行输入:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

测试可以返回正确的页面代码。如果将hello的属性值改为ok,再次访问就会报404错误,证明路由需要匹配正则表达式才会进行路由。

● 通过请求方法匹配

路由断言工厂接收一个参数,即需要匹配HTTP方法。通过POST、GET、PUT、DELETE等不同的请求方式来进行路由。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

使用curl测试(#curl默认以GET的方式去请求),命令行输入:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

测试返回页面代码,证明匹配到路由。

我们再以POST的方式请求测试。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

返回404错误表示没有找到,证明没有匹配上路由。

● 通过Header属性匹配

路由断言工厂接收两个参数,分别是请求头名称和正则表达式。

Header Route Predicate和Cookie Route Predicate一样,也是接收2个参数:一个header的属性值和一个正则表达式。这个属性值和正则表达式匹配则执行。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

● 通过Host路由匹配

Spring Cloud Gateway 可 以 根 据 Host 名 进 行 匹 配 转 发 , HostRoute Predicate接收一组参数、一组匹配的域名列表。它通过参数中的主机地址作为匹配规则。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

使用curl测试,命令行输入:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

通过测试以上两种Host设置方式,均可匹配到host_route,去掉host参数则会报404错误。

● 时间匹配

Predicate支持设置时间,在请求转发时,先判断这个时间与我们设置的时间,然后进行转发,所以又细分为设置时间后断言、设置时间前断言、设置时间之间断言。

设置时间后断言:从After Route Predicate Factory中获取一个UTC时间格式的参数,当请求的当前时间在配置的UTC时间之后,则成功匹配,否则不能成功匹配。下面是实例配置:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

设置时间前断言:从Before Route Predicate Factory中获取一个UTC时间格式的参数,当请求的当前时间在配置的UTC时间之前,则成功匹配,否则不能成功匹配。下面是实例配置:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

设置时间之间断言:从Between Route Predicate Factory中获取一个UTC时间格式的参数,当请求的当前时间在配置的UTC时间之间,则成功匹配,否则不能成功匹配。下面是实例配置:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

● 通过Cookie匹配

Cookie路由断言会取两个参数,一个是Cookie name,一个是正则表达式,路由规则是通过获取的对应Cookie name值和正则表达式进行匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

● 通过IP地址匹配

RemoteAddr Route Predicate Factory配置一个IPv4或者IPv6网段的字符串或者IP地址。当请求的IP地址在网段之内或者与配置的IP地址相同,匹配成功,则进行转发,否则不进行转发。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

可以将curl localhost:8080设置为本机的IP地址进行测试,如果请求的远程地址是192.168.1.30,则此路由将匹配。

GatewayFilter与GlobalFilter

Spring Cloud Gateway 中 有 两 种 Filter , 一 种 是GlobalFilter(全局过滤器),一种是GatewayFilter。GlobalFilter默认对所有路由有效,GatewayFilter需要通过路由分组指定。

GlobalFilter接口与GatewayFilter具有相同的签名,是有条件地应用于所有路由的特殊过滤器。

当请求进入路由匹配逻辑时,Web Handler会将GlobalFilter的所有实例和所有GatewayFilter路由特定实例添加到Filter Chain组件。Filter组合执行的顺序由Ordered接口决定,可以通过getOrder方法或使用@Order注释来设置。Spring Cloud Gateway通过执行过滤器将逻辑分为“前置”和“后置”阶段,优先级较高的前置过滤器会优先被执行,而优先级较高的后置过滤器的执行顺序正好相反,最后执行。

GatewayFilter Factories

过滤器允许以某种方式修改传入的HTTP请求或返回的HTTP响应。

过滤器的作用域是某些特定路由。Spring Cloud Gateway包括许多内置的过滤器工厂。

● 实现前缀修改(增加前缀、去掉前缀)

PrefixPathGatewayFilterFactory及StripPrefixGatewayFilterFactory 是 一 对 处 理 请 求 URL 的 前 缀 的Filter工厂,前者添加前缀,后者去除前缀。

配置文件application.yml如下:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

○ PrefixPathGatewayFilterFactory允许你在对应的路由请求前增加前缀。例如实例配置中的请求/hello,最后转发到目标服务的路径变为/mypath/hello。

○ StripPrefixGatewayFilterFactory允许你在对应的路由请求前去除前缀,例如实例配置中的请求/name/bar/foo,去除前面两个前缀后,最后转发到目标服务的路径为/foo。

● 实现请求头内容添加和改写

AddRequestHeader GatewayFilter Factory采用一对名称和值作为参数,配置文件application.yml如下:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

对于所有匹配的请求,将在向下游请求的头内容中添加xrequest-foo:bar header。

● 实现请求体内容添加和改写

AddRequestParameter GatewayFilter Factory采用一对名称和值作为参数,配置参数application.yml如下:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

对于所有匹配的请求,将向下游请求添加foo=bar查询字符串。

● 实现熔断降级

Hystrix GatewayFilter允许向网关路由引入Hystrix,保护服务不受级联故障的影响,并允许在下游故障时提供fallback响应。要在项 目 中 启 用 Hystrix 网 关 过 滤 器 , 需 要 向 Hystrix 的 依 赖 HystrixGatewayFilter Factory添加一个name参数,即HystrixCommand的名称,配置文件application.yml如下:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

当调用hystrixfallback时,将转发到/incaseoffailureusethis。注意,这个示例还演示了通过目标URI上的“lb”前缀使Spring Cloud Netflix Ribbon客户端实现负载均衡。主要场景是网关应用程序中的内部控制器或处理程序使用fallbackUri,它也可以将请求重新路由到外部应用程序中的控制器或处理程序。

● 分布式限流

SpringCloudGateway内置的RequestRateLimiterGatewayFilterFactory提供限流的能力,基于令牌桶算法实现。目前它内置的RedisRateLimiter,依赖Redis来存储限流配置和统计数据。当然你也可以实现自己的RateLimiter,只需实现Spring Cloud Gateway 自 带 的 RateLimiter 接 口 或 者 继 承AbstractRateLimiter。

首先,添加Maven依赖。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

其次,添加限流配置。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

最后,完成对Path的KeyResolver(可以通过KeyResolver来指定限流的Key),实现对特定Path下的限流控制配置。在过滤器中可以配置一个可选的KeyResolver,KeyResolver在配置中根据名称使用SpEL引用Bean。#{@myKeyResolver}是引用名为“pathKeyResolver”的Bean的SpEL表达式。KeyResolver接口允许使用可插拔策略来派生限制请求的Key。代码如下:

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

Spring Cloud Gateway的动态路由

下面介绍基于Spring Cloud Gateway的动态路由实现(相关代码将会随书附带),实现方式与Zuul的动态路由实现方式类似,具有比Zuul更加灵活的路由策略和匹配模式。这两种解决方案如下。

●通过SpringCloudGateway提供的GatewayControllerEndpointduan端点功能,实现路由的增删改 查 , 或 者 自 己 实 现 ApplicationEventPublisherAware 接口,实现自定义的路由操作方法。具体可以参考源码:GatewayControllerEndpointduan类。

● 通过实现RouteDefinitionRepository接口,实现自定义的Repository类,实现从数据库或者缓存中动态加载路由信息的功能。架构模式与Zuul的动态路由采用相似的路由加载策略,架构流程图如下。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

动态路由思路及解决方案具体如下。

首先,Admin作为前端管理界面,将用户对路由的添加、修改等操作通过RouteAsynchService存储到DB中。DB中的存储结构如下图所示。

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析

字段映射关系如下。

● routeid:标识路由的唯一ID,可以根据路由ID查找路由,路由ID不能重复。

● routename:应用名称是标识路由的别名,是非必选项。

● routeorder:对应RouteDefinition中的order属性。

● routestatus:路由状态,包括

本文来自投稿,不代表重蔚自留地立场,如若转载,请注明出处https://www.cwhello.com/97297.html

如有侵犯您的合法权益请发邮件951076433@qq.com联系删除

(0)
程序员高级码农II程序员高级码农II订阅用户
上一篇 2022年9月13日 06:04
下一篇 2022年9月13日 06:04

相关推荐

联系我们

QQ:951076433

在线咨询:点击这里给我发消息邮件:951076433@qq.com工作时间:周一至周五,9:30-18:30,节假日休息