• 细到不能再细的 Spring Cloud Gateway 原理分析(内含多张图片讲解)


    前言

    本文会通过图文的方式由浅入深的描述 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    正文

    一、Gateway 在微服务中的作用

    在这里插入图片描述

    1. 请求方 发送一个请求到达 gateway 时,gateway 根据 配置的路由规则,找到 对应的服务名称
    2. 当某个服务存在多个实例时,gateway 会根据 负载均衡算法(比如:轮询)从中挑选出一个实例,然后将请求 转发 过去。
    3. 服务实例返回的的响应结果会再经过 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 章节的分析, 可以将官网的描述成如下大白话:

    1. 实现网关必将涉及到网络通信,众所周知 Netty 是一款 出色 的网络通信框架。
    2. 为了提升网关的性能, gateway 使用到了响应式编程。
    3. 而 WebFlux 框架底层就使用了高性能的 Reactor 模式通信框架 Netty,所以可以直接拿来用。

    PS: 至于什么是响应式编程, 为什么 gateway 基于这些技术能够实现高性能, 这些不是本文探讨的内容,感兴趣的读者可以自行去了解。

    那么, 如何理解 Spring WebFlux,我们暂且就把它当做 Spring WebMVC。一个 web 框架。
    他们之间很重要的一个区别就在于 webmvc 我们一般会基于 tomcat 容器去完成底层的网络通信, 而 webflux 是基于 Netty

    2.3 gateway 是如何工作的

    我们先来看下官网的描述:
    在这里插入图片描述

    1. 客户端向 Spring Cloud Gateway 发出请求。
    2. 如果 Gateway Handler Mapping 找到与请求相匹配的路由,将其发送到 Gateway Web Handler。
    3. Handler 再通过指定的 过滤器链 来将请求发送到我们实际的服务执行业务逻辑,然后返回。
    4. 过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。

    从图中可以看出, 在 gateway 视角里,它在处理请求时, 划分成如下三大角色:

    • HandlerMapping
    • Handler
    • Filter Chain

    此时, 如果熟悉 Spring MVC 工作原理的可以看出,它和 Springmvc 的核心工作流程是类似的。

    2.4 webflux 的工作原理以及 gateway 是如何基于它进行扩展

    上面说到, gateway 底层还是基于 webflux。我们首先简单了解下 webflux 的工作原理, 然后延伸到 gateway 是如何基于 webflux 做扩展的。

    在这里插入图片描述

    以上是 webflux 处理请求的代码链路。我们着重看下标有颜色的类。

    1. 接受请求的关键类是 ReactorHttpHandlerAdapter,他的作用是将 netty 的请求、响应转为 http 的请求、响应, 并交给后面的类处理。
    2. 标记 ① 位置的过滤器链是 webflux 自身的。
    3. 标记 ③ 对应的 FilteringWebHandler 是 gateway 对 webflux 的扩展。
    4. 标记 ②③④ 整理对应最上面的 gateway 的工作流程。

    简单总结:

    1. webflux 在处理请求时,会先执行自身的过滤器链
    2. 然后通过 HandlerMapping 拿到对应的 Handller
    3. gateway 通过 第二步 webflux 提供的扩展点, 实现了对应的接口, 最终导致 代码链路 走到了 gateway 中定义的 Handler, 此时 gateway 就可以对到来的请求 “为所欲为” 了。
    4. gateway 通过定义自己的过滤器链,从而又方便了开发者对其进行自定义扩展。

    如果没看懂, 可以看完下面的内容, 再回过头来看本章节。

    三、Gateway 的核心组件

    Gateway 有三个比较核心的组件, 可以结合如下路由配置看一看:

    spring:
      cloud:
        gateway:
          routes:
          - id: test_route
            uri: lb://service-A
            predicates:
             - Path=/hello
            filters:
            - SetRequestHeader=X-Request-Red, Blue
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 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 可以使用不同的参数,因此会创建不同的实例。

    围绕上述三个组件, 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 区分开)
        • RoutePredicateHandlerMappingorg.springframework.cloud.gateway.handler.FilteringWebHandler , 这两个类是对 webflux 中两个组件的扩展实现,后续会说到具体作用。
      • 启动 Netty Server, 负责监听请求
    • 当 gateway 接收到请求时
      • webflux 经过一层层处理后,然后会去调用 HandlerMapping 接口,拿到对应的 Handler。最后调用 Handlerhandle 方法进行业务处理。
      • gateway 通过实现 HandlerMappingHandler 两个接口,从而把处理请求的 活儿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<>();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public class Route implements Ordered {
    	// ....
    
    	private final AsyncPredicate<ServerWebExchange> predicate;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    4.2 RouteLocator

    RouteLocator 接口中定义了获取路由配置的方法,RouteLocator 有不同的实现,对应了不同的定义路由的方式。

    public interface RouteLocator {
    
    	Flux<Route> getRoutes();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    前文中我们提到,定义路由的其中一个方式是通过 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    RouteDefinitionRouteLocatorRouteLocator 另一种常用的实现 。这种实现依赖于 RouteDefinitionLocator 来提供 RouteDefinition ,再由 RouteDefinition 构造路由。

    CompositeRouteLocator 会把所有的 RouteLocator 的实现组合起来,再缓存到 CachingRouteLocator 中 。

    因此当我们调用 getRoutes 方法获取路由集合时, 就会产生如下的调用关系:

    在这里插入图片描述

    4.3 RouteDefinitionLocator

    RouteDefinitionLocator 接口定义了获取 RouteDefinition 的方法。

    public interface RouteDefinitionLocator {
    	Flux<RouteDefinition> getRouteDefinitions();
    }
    
    • 1
    • 2
    • 3

    前面我们多次提到 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 的底层是基于 NettyReactor, 可以有效的提升网关的性能。

    另外,本文的不足之处包括但不限于如下几点:

    1. 没有详细说明 Spring Cloud Gateway 高性能的原因是什么。
    2. 没有对 gateway 如何实现用户鉴权、灰度发布等功能进行说明。
    3. 没有足够的源码分析。
    4. 没有说明如何对 gateway 进行扩展实现。

    当然, 后面如果有条件会对以上几点进行补充说明。

  • 相关阅读:
    java计算机毕业设计天津城建大学校友录管理系统源程序+mysql+系统+lw文档+远程调试
    springmvc请求转发和重定向的四种跳转方式
    【Java基础】时间日期类之Date类、SimplDateFormat类、Calendar类及二月天案例
    sql分词查询,实现类似ES的效果
    【线性代数】【二】2.7 矩阵的秩
    LaTeX公式编辑器ver1.6.5 编辑器 -----TeX公式编辑网站
    一次jenkins-kubernetes服务报错排查记录 (Request Header Fields Too Large)
    Docker部署和全部命令
    JS逆向之巨量星图sign签名
    看了扎克伯格的Avatar,我更想在VR里当大猩猩
  • 原文地址:https://blog.csdn.net/cnm10050/article/details/127261680