前言
本文会通过图文的方式由浅入深的描述 Spring Cloud Gateway (以下简称 gateway)的基本原理。
本文不涉及 gateway 的任何示例代码, 如有需要请参考官网 sample 。
阅读前, 需要读者提前掌握 gateway 的基本使用。至少要能读懂如下配置的含义:
spring:
cloud:
gateway:
routes:
- id: test_route
uri: lb://service-A
predicates:
- Path=/hello
filters:
- SetRequestHeader=X-Request-Red, Blue
正文
一、Gateway 在微服务中的作用
- 当 请求方 发送一个请求到达 gateway 时,gateway 根据 配置的路由规则,找到 对应的服务名称。
- 当某个服务存在多个实例时,gateway 会根据 负载均衡算法(比如:轮询)从中挑选出一个实例,然后将请求 转发 过去。
- 服务实例返回的的响应结果会再经过 gateway 转发给请求方。
以上便是 gateway 最基本的作用,它处理请求是逻辑是根据 配置的路由 对请求进行 预处理 和 转发
除此之外,还包括但不限于如下功能:
- 权限校验
- 限流熔断
- 请求重试。
- 监控统计
- 灰度流量
以上功能皆非本文讨论的重点内容,仅在此提及一下。
二、Gateway 的工作原理
在讨论 gateway 工作原理之前, 我们先思考下, 如果让我们制作一个简单的网关应用, 实现方式有哪些。
2.1 实现一个网关的几种方式
根据上一章节末的描述可知, gateway 主要用于请求的转发处理。因此这里就涉及了网络通信的知识。
2.1.1 基于 socket API 实现
2.1.2 基于 Netty 实现
2.1.3 基于 Web 框架
2.2 gateway 的底层实现原理
先简单翻译一下摘自 gateway 官网的描述:
SpringCloud Gateway 是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关。为了提升网关的性能,SpringCloud Gateway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty。
然后我们结合 2.1 章节的分析, 可以将官网的描述成如下大白话:
- 实现网关必将涉及到网络通信,众所周知
Netty
是一款 出色 的网络通信框架。 - 为了提升网关的性能, gateway 使用到了响应式编程。
- 而 WebFlux 框架底层就使用了高性能的
Reactor
模式通信框架Netty
,所以可以直接拿来用。
PS: 至于什么是响应式编程, 为什么 gateway 基于这些技术能够实现高性能, 这些不是本文探讨的内容,感兴趣的读者可以自行去了解。
那么, 如何理解 Spring WebFlux,我们暂且就把它当做 Spring WebMVC。一个 web 框架。
他们之间很重要的一个区别就在于 webmvc 我们一般会基于 tomcat
容器去完成底层的网络通信, 而 webflux 是基于 Netty
。
2.3 gateway 是如何工作的
我们先来看下官网的描述:
- 客户端向 Spring Cloud Gateway 发出请求。
- 如果 Gateway Handler Mapping 找到与请求相匹配的路由,将其发送到 Gateway Web Handler。
- Handler 再通过指定的 过滤器链 来将请求发送到我们实际的服务执行业务逻辑,然后返回。
- 过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
从图中可以看出, 在 gateway 视角里,它在处理请求时, 划分成如下三大角色:
- HandlerMapping
- Handler
- Filter Chain
此时, 如果熟悉 Spring MVC 工作原理的可以看出,它和 Springmvc 的核心工作流程是类似的。
2.4 webflux 的工作原理以及 gateway 是如何基于它进行扩展
上面说到, gateway 底层还是基于 webflux。我们首先简单了解下 webflux 的工作原理, 然后延伸到 gateway 是如何基于 webflux 做扩展的。
以上是 webflux 处理请求的代码链路。我们着重看下标有颜色的类。
- 接受请求的关键类是
ReactorHttpHandlerAdapter
,他的作用是将 netty 的请求、响应转为 http 的请求、响应, 并交给后面的类处理。 - 标记 ① 位置的过滤器链是 webflux 自身的。
- 标记 ③ 对应的
FilteringWebHandler
是 gateway 对 webflux 的扩展。 - 标记 ②③④ 整理对应最上面的 gateway 的工作流程。
简单总结:
- webflux 在处理请求时,会先执行自身的过滤器链
- 然后通过 HandlerMapping 拿到对应的 Handller
- gateway 通过 第二步 webflux 提供的扩展点, 实现了对应的接口, 最终导致 代码链路 走到了 gateway 中定义的 Handler, 此时 gateway 就可以对到来的请求 “为所欲为” 了。
- gateway 通过定义自己的过滤器链,从而又方便了开发者对其进行自定义扩展。
如果没看懂, 可以看完下面的内容, 再回过头来看本章节。
三、Gateway 的核心组件
Gateway 有三个比较核心的组件, 可以结合如下路由配置看一看:
spring:
cloud:
gateway:
routes:
- id: test_route
uri: lb://service-A
predicates:
- Path=/hello
filters:
- SetRequestHeader=X-Request-Red, Blue
-
Route
gateway 中可以配置多个Route
。一个Route
由路由 id,转发的 uri,多个Predicates
以及多个Filters
构成。处理请求时会按优先级排序,找到第一个满足所有Predicates
的 Route。 -
Predicates
表示路由的匹配条件,可以用来匹配请求的各种属性,如请求路径、方法、header 等。一个Route
可以包含多个Predicates
,多个Predicates
最终会合并成一个。 -
Filter
过滤器包括了处理请求和响应的逻辑,可以分为 pre 和 post 两个阶段。多个Filter
在 pre 阶段会按优先级高到低顺序执行,post 阶段则是反向执行。gateway 中的 Filter 分为如下两种:- 全局 Filter: 每种全局
Filter
在 gateway 中只会有一个实例,会对所有的Route
都生效。 - 路由 Filter: 路由
Filter
是针对Route
进行配置的,不同的Route
可以使用不同的参数,因此会创建不同的实例。
- 全局 Filter: 每种全局
围绕上述三个组件, gateway 又衍生出了一些其他组件。
- RouteLocator
- RouteDefinitionLocator
- RoutePredicateHandlerMapping
- FilteringWebHandler
具体作用我们会在下面一一说明。
接下来,我们通过对上图进行讲解, 来详细介绍各个组件在 gateway 中的作用。
首先, gateway 本质就是一个 Springboot
应用, 他是通过 webflux 框架处理请求和响应,而 webflux 底层是基于 Netty
。
- 当 gateway 启动时
- Spring 会装载
GatewayAutoConfiguration
中配置的一些必要的组件Bean
。 比如:-
GatewayProperties
, 他里面保存了 gateway 的全部配置(其中就有路由配置信息)。 -
GlobalFilter
, gateway 默认的一些全局过滤器。 -
RouteDefinitionLocator
, 通过加载路由配置(比如读取 yaml 文件), 拿到RouteDefinition
, 里面是对路由的定义。 -
RouteLocator
, 负责组装Route
对象,Route
对象中保存的是路由相关的信息。后续进行路由操作都是基于此对象。(请注意和RouteDefinition
区分开) -
RoutePredicateHandlerMapping
和org.springframework.cloud.gateway.handler.FilteringWebHandler
, 这两个类是对webflux
中两个组件的扩展实现,后续会说到具体作用。
-
- 启动 Netty Server, 负责监听请求
- Spring 会装载
- 当 gateway 接收到请求时
-
webflux
经过一层层处理后,然后会去调用HandlerMapping
接口,拿到对应的Handler
。最后调用Handler
的handle
方法进行业务处理。 - gateway 通过实现
HandlerMapping
和Handler
两个接口,从而把处理请求的 活儿 从webflux
手中接过来。 - 在上一步中, gateway 已经根据请求信息, 从路由集合中挑选出来了一个匹配的路由,路由信息中包含了一个过滤器链。
- 在
Handler#handle
方法中,客户端发来的请求会经过上一步中过滤器链, 最终经过层层处理的请求会转发到对应服务中。
-
四、gateway 的更多细节
4.1 RouteDefinition 和 Route
RouteDefinition 定义了一个路由应该包含哪些匹配条件和过滤器,以及这些匹配条件和过滤器使用的参数, 它表示的是一个名词定义。在使用时 Gateway进行路由时, 会根据 RouteDefinition 对象提供的定义构造出 Route 对象,而 Route 里面提供了很多动作。
并且我们在前面提到: “一个 Route
可以包含多个 Predicates
,多个 Predicates
最终会合并成一个。因此我们可以看到,关于 Predicates,RouteDefinition 里面定义的是一个集合, 而 Route 中只是一个对象。
public class RouteDefinition {
// ...
private List<PredicateDefinition> predicates = new ArrayList<>();
}
public class Route implements Ordered {
// ....
private final AsyncPredicate<ServerWebExchange> predicate;
}
4.2 RouteLocator
RouteLocator
接口中定义了获取路由配置的方法,RouteLocator 有不同的实现,对应了不同的定义路由的方式。
public interface RouteLocator {
Flux<Route> getRoutes();
}
前文中我们提到,定义路由的其中一个方式是通过 RouteLocatorBuilder
提供的 API 来构建具体的 Route
。
如下代码中定义了一个路由,其中包含了一个 path 匹配条件,以及一个添加响应 header 的 filter,请求转发的目标地址是 https://blog.csdn.net
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("route-id", r -> r.path("/test")
.filters(f -> f.addResponseHeader("X-TestHeader", "foobar"))
.uri("https://blog.csdn.net")
)
.build();
}
而 RouteDefinitionRouteLocator
是 RouteLocator
另一种常用的实现 。这种实现依赖于 RouteDefinitionLocator
来提供 RouteDefinition
,再由 RouteDefinition
构造路由。
CompositeRouteLocator
会把所有的 RouteLocator
的实现组合起来,再缓存到 CachingRouteLocator
中 。
因此当我们调用 getRoutes
方法获取路由集合时, 就会产生如下的调用关系:
4.3 RouteDefinitionLocator
RouteDefinitionLocator
接口定义了获取 RouteDefinition
的方法。
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
前面我们多次提到 PropertiesRouteDefinitionLocator
可以通过解析 gateway 的配置文件中的路由配置拿到 RouteDefinition
对象集合
同上面的 RouteLocator
一样, 当 gateway 中有多个 RouteDefinitionLocator
实现时 , 同样会被 CompositeRouteDefinitionLocator
组合起来。
4.4 Filter
gateway 处理请求和响应的核心逻辑就在 Filter 中。gateway 本身实现提供了基础通用的过滤器,可以直接配置使用。 比如在请求前后, 分别添加请求头和响应头
我们再来看几个比较有意思的全局过滤器:
-
NettyRoutingFilter
在这个过滤器里面, 会发送转发请求到具体的 uri。 -
ReactiveLoadBalancerClientFilter
当 gateway 接入微服务时, 如果我们请求的服务存在多个实例,会在这里面进行负载均衡的处理。
总结
本文通过图文结合的方式, 介绍了 Spring Cloud Gateway 的基本工作原理。
- gateway 的本质就是基于
Spring Webflux
提供的扩展点,从而将请求与响应的工作转到自己手中。 - gateway 通过 过滤器链 进行具体逻辑处理,并且开发者也可以实现自己的过滤器,然后插入到过滤器链中的某个位置, 从而对请求和响应进行加工。
-
Spring Webflux
的底层是基于Netty
和Reactor
, 可以有效的提升网关的性能。
另外,本文的不足之处包括但不限于如下几点:文章来源:https://uudwc.com/A/yRm
- 没有详细说明 Spring Cloud Gateway 高性能的原因是什么。
- 没有对 gateway 如何实现用户鉴权、灰度发布等功能进行说明。
- 没有足够的源码分析。
- 没有说明如何对 gateway 进行扩展实现。
当然, 后面如果有条件会对以上几点进行补充说明。文章来源地址https://uudwc.com/A/yRm