门面模式Api网关(SpringCloudGateway)

1. 前言

当前通过Eureka、Nacos解决了服务注册和服务发现问题,使用Spring Cloud LoadBalance解决了负载均衡的需求,同时借助OpenFeign实现了远程调用。然而,现有的微服务接口都直接对外暴露,容易被外部访问。为保障对外服务的安全性,通常在服务端实现的微服务接口会带有一定的权限校验机制。由于应用拆分成多个微服务,每个微服务都需要实现权限校验逻辑,导致当逻辑需要修改时,需要在多个应用中进行修改,增加了开发人员的负担。
比如企业管理
外部人员去公司办理业务, 公司需要先核实对方的身份再去进行办理.
最开始只有一个员工, 这个员工核实之后直接办理即可. (单体架构)
随着公司的发展, 划分了多个部门, 每个部门负责的事情不同, 每个部门都需要先核实对方的身份再进行办理. (微服务架构)
这个流程存在一些问题:

    1. 办事效率低
    1. 增加了员工的工作流程

我们对此进行改进, 设立前台, 统一由前台来进行身份的校验. 前台身份校验通过后, 其他部门就设置信任, 直接办理。

接下来我将会介绍一门新的技术: API网关 SpringCloudGateway

在微服务架构中,API 网关扮演着至关重要的角色,它是客户端和后端服务之间的门面,负责统一处理所有的请求和响应。Spring Cloud Gateway作为Spring Cloud生态系统中的一个全新项目,提供了强大而灵活的方式来构建 API 网关服务。本文将深入介绍Spring Cloud Gateway的功能、特点以及如何应用于微服务架构中。

2. 功能和特点

Spring Cloud Gateway提供了丰富的功能和特性,其中包括:

  • 动态路由: 可以根据需求动态地将请求路由到相应的后端服务,实现请求的分发和转发。

  • 权限控制: 可以通过实现对请求的安全控制,包括认证、鉴权、请求加密等功能,保障系统的安全性。

  • 负载均衡: 集成了负载均衡的功能,可以将请求分发到多个后端服务实例中,提高系统的可用性和性能。

  • 断路器: 支持断路器模式,可以在后端服务不可用时进行降级处理,避免整个系统的崩溃。

  • 统一的认证和授权: 可以集成统一的认证和授权机制,保护系统的安全性。

  • 监控和日志: 支持监控和日志记录,帮助开发者排查问题和优化系统性能。

  • 过滤器处理: 可以通过自定义的过滤器对请求进行预处理、后处理、权限控制、日志记录等操作,实现对请求的统一管理和处理。

  • 限流:可以通过过滤器和流量算法实现对流量的控制,防止流量过大导致系统崩溃。请求流量过高时, 按照网关中配置微服务能够接受的流量进行放行, 避免服务压力过大

    类似前台的工作

    1. 权限控制: 身份验证。
    2. 动态路由: 根据外来客户的需求, 把客户带到指定的部门去处理。
    3. 负载均衡: 一个部门有很多人时, 前台会帮客客户选择具体某个人处理。
    4. 限流: 公司到访客⼾较多时, 进⾏流量限制, ⽐如告知明天再来。

3. 什么是API网关?

API网关(简称网关)也是⼀个服务, 通常是后端服务的唯一入口. 它的定义类似设计模式中的Facade模式 (门面模式, 也称外观模式). 它就类似整个微服务架构的门面模式, 所有的外部客户端访问, 都需要经过它来进行调度和过滤.

4. 简单的使用步骤

3.1 创建一个新的模块

3.2 引入依赖

XML 复制代码
        <!--引入spring_cloud_gateway的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    <!--nacos的依赖用于动态路由-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    <!--负载均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

引入nocos的依赖和负载均衡的依赖就是因为我们的动态路由控制负载均衡均根据二者实现的。

3.3 修改配置文件

复制代码
server:
  port: 10030
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
#    配置路由的规则
    gateway:
#      这里配置了一个路由规则,将请求转发到名为"order-service"的服务上。
#  当请求的路径以"/order/"开头时,会被路由到"order-service"服务上。
      routes:
        - id: order-service #路由规则id,随便起不重复即可
#  lb 表示负载均衡(Load Balancing)的意思。它告诉Spring Cloud Gateway使用负载均衡的方式将请求分发到多个实例中。
          uri: lb://order-service # 指定路由到哪个机器里
          # 条件
          predicates:
            - Path=/order/**,/feign/**  # ,后面配置多个路径

配置字段说明:

  • id : 自定义路由ID, 保持唯一
  • uri: 目标服务地址, 支持普通URI 及 lb://应用注册服务名称 . lb表示负载均衡, 使用 lb:// 方式表示从注册中心获取服务地址.
  • predicates: 路由条件, 根据匹配结果决定是否执行该请求路由, 上述代码中, 我们把符合Path规则的 ⼀切请求, 都代理到uri参数指定的地址.

4. 路由断言工厂

spring:

cloud:

gateway:

routes:

  • id: after-route

uri: https://example.org

predicates:

  • After=2024-06-05T12:00:00+08:00[Asia/Shanghai]

例如上述 -After就是路由断言工厂,也就是路由的条件符合条件才可以访问。

|---------|----------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
| 名称 | 说明 | 示例 |
| After | 这个工厂需要一个日期时间(Java 的 ZonedDateTime对象), 匹配指 定⽇期之后的请求 | predicates: - After=2017-01-20T17:42:47.789- 07:00[America/Denver] |
| Before | 匹配指定日期之前的请求 | predicates: - Before=2017-01-20T17:42:47.789- 07:00[America/Denver] |
| Between | 匹配两个指定时间之间的请求, datetime2 的参数必须在 datetime1 之后 | predicates: - Between=2017-01-20T17:42:47.789- 07:00[America/Denver], 2017-01- 21T17:42:47.789-07:00[America/Denver] |
| Cookie | 请求中包含指定Cookie, 且该 Cookie值符合指定的正则表达式 | predicates: - Cookie=chocolate, ch.p |
| Header | 请求中包含指定Header, 且该 Header值符合指定的正则表达式 | predicates: - Header=X-Request-Id, \d+ |
| Host | 请求必须是访问某个host(根据请 求中的Host 字段进行匹配) | predicates: - Host=**.somehost.org,**.anotherhost.or g |
| Method | 匹配指定的请求方式 | predicates: - Method=GET,POST |
| Path | 匹配指定规则的路径 | predicates: - Path=/red/{segment},/blue/{segment} |

5. 网关过滤器工厂

Predicate决定了请求由哪⼀个路由处理, 如果在请求处理前后需要加⼀些逻辑, 这就是Filter(过滤器)的作⽤范围了.
Filter分为两种类型: Pre类型和Post类型.
Pre类型过滤器: 路由处理之前执行(请求转发到后端服务之前执行), 在Pre 类型过滤器中可以做鉴权, 限流等.
Post类型过滤器: 请求执⾏完成后, 将结果返回给客户端之前执
比如去景区玩

  1. 进景区之前需要先安检, 验票(鉴权), 如果今日进景区的人超过了规定的人数, 就会进⾏限流
  2. 接下来进景区游玩
  3. 游玩之后, 对景区服务进行评价

1 就类似Pre类型过滤器, 3就类似Post类型过滤器, 过滤器可有可无

Spring Cloud Gateway 中内置了很多Filter, 用于拦截和链式处理web请求. 比如权限校验, 访问超时
等设定.
Spring Cloud Gateway从作用范围上, 把Filter可分为GatewayFilter 和GlobalFilter.

  1. GatewayFilter: 应用到单个路由或者⼀个分组的路由上.
  2. GlobalFilter: 应用到所有的路由上, 也就是对所有的请求⽣效

GatewayFilter 同 Predicate 类似, 都是在配置文件 application.yml 中配置,每个过滤
器的逻辑都是固定的. 比如 AddRequestParameterGatewayFilterFactory 只需要在配置文件
中写 AddRequestParameter , 就可以为所有的请求添加一个参数, 我们先通过一个例子来演示GatewayFilter如何使用。

GlobalFilter是一种应用到所有路由上的过滤器,它会对所有的请求生效,而不是仅应用到单个路由或者一个分组的路由上。这意味着,不管是哪个路由,GlobalFilter都会对请求进行处理。

在Spring Cloud Gateway中,GlobalFilter可以用来实现一些全局的功能,比如安全认证、日志记录、请求转发等。与GatewayFilter相比,GlobalFilter的逻辑不是固定的,而是可以自定义的,因此它具有更大的灵活性和功能性。

举个例子,你可以创建一个自定义的GlobalFilter来记录每个请求的访问日志,并将日志信息保存到数据库中。这样无论是哪个路由的请求,都会被这个GlobalFilter捕获并进行相应的处理。

在配置文件application.yml中,GlobalFilter的配置方式与GatewayFilter类似,只需要在其中配置相应的过滤器名称即可。通过这种方式,GlobalFilter会应用到所有的路由上,对所有的请求生效。

演示示例:


该filter只添加在了 product-service 路由下, 因此只对 product-service 路由⽣效, 也就是
对 /product/** 的请求⽣效.

6.常见的过滤信息参数设置

|----------------------|----------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 名称 | 说明 | 示例 |
| AddRequestHeader | 为当前请求添加Header | - AddRequestHeader=X-Request-red, blue 参数: Header的名称及值 |
| AddRequestParameter | 为当前请求添加请求参数 | - AddRequestParameter=red, blue 参数: 参数的名称及值 |
| AddResponseHeader | 为响应结果添加Header | - AddResponseHeader=X-Response-Red, Blue 参数: Header的名称及值 |
| RemoveRequestHeader | 从当前请求删除某个Header | - RemoveRequestHeader=X-Request-Foo 参数: Header的名称 |
| RemoveResponseHeader | 从响应结果删除某个Header | - RemoveResponseHeader=X-Response-Foo 参数: Header的名称 |
| RequestRateLimiter | 为当前网关的所有请求 执⾏限流过滤, 如果被限流,默认提供了 RedisRateLimiter的限 流实现, 采采令牌桶算法实现限流功能. 此处不做 | filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20 redis-rate-limiter.requestedTokens: 1 redis-rate-limiter.replenishRate : 令牌填充速度, 即 每秒钟允许多少个请求(不丢弃任何请求) redis-rate-limiter.burstCapacity : 令牌桶容量, 即每秒用户最大能够执行的请求数量(不丢弃任何请求). 将此值设置 为零将阻止所有请求 redis-rate-limiter.requestedTokens : 每次请求占用几个令牌, 默认为 1 。 |
| Retry | 针对不同的响应进行重 试. 当后端服务不可用 时, 网关会根据配置参数来发起重试请求. | filters: - name: Retry args: retries: 3 statuses: BAD_REQUEST retries: 重试次数, 默认为3 status:HTTP请求返回的状态码, 针对指定状态码进行重试. 对应 org.springframework.http.HttpStatus |
| RequestSize | 设置允许接收最大请求包的大小. 如果请求包大小超过设置的值, 则返回 请求包大小, 单位为字 节, 默认值为5M. | filters: - name: RequestSize args: maxSize: 5000000 |
| 默认过滤器 | 添加一个filter并将其应用于所有路由, 这个属性需要一个filter的列表, | |

  1. 限流算法的介绍
    实例:一分钟最高一千次请求
  2. 固定窗口
    每分钟的窗口大小为1000,下一分钟清空窗口。
    存在的问题:比如你前59秒都没人访问,59-60出现1000个人。然后重置窗口,60-61又出现1000个人访问,就会出现限流失策。
  3. 滑动窗口
    每一秒滑动一次,滑动的时候删除最前方一秒的数据,然后窗口一直在进窗口的时候进行判断是否大于1000,大于一千拒绝访问或者mq排队。
    存在问题:一秒就相当于一秒的固定窗口,我可以在你移动之前出现流量顶峰,比如0.09s-0.1s有一千次。0.1s-0.11s又有一千次。
  4. 漏桶算法
    有一个固定容量的桶,用来存放待处理的请求或数据包。当请求到达时,如果桶还有剩余空间,则将请求放入桶中,如果桶已满,则拒绝该请求或丢弃数据包。桶以固定的速率向外漏水(即处理请求或发送数据包),这样就限制了流量的速率。
    存在问题:漏桶算法虽然可以限制流量的速率,但它不会关心请求的处理时间,并且不能处理突发流量的情况。比如桶里无论有多少数据,他都是按照固定速率去漏。
  5. 令牌桶算法
    有一个固定容量的桶,里面存放着令牌(tokens)。桶以固定的速率产生令牌,并且最多存放固定数量的令牌。当请求到达时,如果桶中有足够的令牌,则允许请求通过,并且从桶中移除相应数量的令牌;如果桶中没有足够的令牌,则拒绝该请求。
    这种算法允许一定程度的突发流量,只要桶中有足够的令牌,即使速率超过了平均速率也是可以的。

总结:

随着微服务架构的广泛应用,API 网关成为了系统架构中的关键组件,用于统一处理所有的请求和响应,实现了诸如动态路由、权限控制、负载均衡、断路器等功能。Spring Cloud Gateway 是 Spring Cloud 生态系统中的一个全新项目,提供了强大而灵活的方式来构建 API 网关服务。

Spring Cloud Gateway 的功能和特点包括:

  1. 动态路由:根据需求动态地将请求路由到相应的后端服务,实现请求的分发和转发。
  2. 权限控制:通过实现对请求的安全控制,包括认证、鉴权、请求加密等功能,保障系统的安全性。
  3. 负载均衡:集成了负载均衡的功能,可以将请求分发到多个后端服务实例中,提高系统的可用性和性能。
  4. 断路器:支持断路器模式,可以在后端服务不可用时进行降级处理,避免整个系统的崩溃。
  5. 统一的认证和授权:可以集成统一的认证和授权机制,保护系统的安全性。
  6. 监控和日志:支持监控和日志记录,帮助开发者排查问题和优化系统性能。

在使用 Spring Cloud Gateway 进行开发时,主要包括以下步骤:

  1. 创建一个新的模块,并引入相应的依赖,其中包括 Spring Cloud Gateway 和用于动态路由的注册中心(如 Nacos),以及负载均衡的依赖。
  2. 修改配置文件,配置网关的端口、注册中心地址以及路由规则等信息。
  3. 配置路由的规则,通过配置文件指定请求的路径和目标服务地址,实现请求的转发。
  4. 可以根据需要使用路由断言工厂,实现更加精细化的路由控制。
  5. 配置网关过滤器工厂,实现对请求的预处理和后处理,包括添加请求头、请求参数、限流等功能。

对于限流算法,常见的有固定窗口、滑动窗口、漏桶算法和令牌桶算法。其中,令牌桶算法是一种常用的限流算法,通过固定容量的令牌桶和固定速率产生令牌来限制请求的处理速率,允许一定程度的突发流量。

相关推荐
AAA修煤气灶刘哥9 分钟前
接口又被冲崩了?Sentinel 这 4 种限流算法,帮你守住后端『流量安全阀』
后端·算法·spring cloud
T_Ghost4 小时前
SpringCloud微服务服务容错机制Sentinel熔断器
spring cloud·微服务·sentinel
喂完待续6 小时前
【序列晋升】28 云原生时代的消息驱动架构 Spring Cloud Stream的未来可能性
spring cloud·微服务·云原生·重构·架构·big data·序列晋升
惜.己20 小时前
Docker启动失败 Failed to start Docker Application Container Engine.
spring cloud·docker·eureka
chenrui3101 天前
Spring Boot 和 Spring Cloud: 区别与联系
spring boot·后端·spring cloud
喂完待续2 天前
【序列晋升】29 Spring Cloud Task 微服务架构下的轻量级任务调度框架
java·spring·spring cloud·云原生·架构·big data·序列晋升
麦兜*2 天前
MongoDB 性能调优:十大实战经验总结 详细介绍
数据库·spring boot·mongodb·spring cloud·缓存·硬件架构
小马爱打代码4 天前
Spring Cloud LoadBalancer 核心原理
spring cloud
小马爱打代码4 天前
Spring Cloud Eureka 核心原理
spring cloud·eureka
AAA修煤气灶刘哥4 天前
后端哭晕:超时订单取消踩过的坑,延迟消息这么玩才对!
后端·spring cloud·rabbitmq