张裕 发表于 2024-6-21 14:29:06

微服务网关Gateway(上)

大家好呀,我是苍何。
这年初,大家都在开始卷简历了,我也看了很多同学的简历,此中有一个同学的简历,我印象最为深刻,他的项目履历中,写了自界说 Gateway 过滤器实现统计接口调用耗时,我刹时就来兴趣了~
要知道利用微服务中的网关过滤器本领来统计接口调用耗时情况,其落地项目和设计思路是很考察对微服务架构团体掌握程度的。
那今天我们就来重点看一看微服务中的网关吧,还是以 PmHub 项目实践深入展开。
为什么需要网关

网关我以为可以理解成是微服务系统的门卫,是微服务架构中一个关键的组件,负责管理和调控外部请求进入内部微服务的流量。为了更好理解,拿个生活中的例子来对比下:
一个大型的购物中心(微服务系统),里面有很多不同的商店(不同的微服务),好比服装店、餐馆、电影院等等。每个商店都有本身独立的入口,如许的好处是每个商店都可以独立运营。但是,假如每个顾客都直接去商店入口没有同一入口,会非常混乱。
而且,购物中心需要对每个商店的顾客流量举行管理,好比防止某些商店人满为患或者同一处置惩罚会员优惠等。
https://img-blog.csdnimg.cn/direct/98b5d1b0e5934e55bb6092814b2400da.webp#pic_center
网关在微服务体系中的具体位置在哪儿呢?
https://img-blog.csdnimg.cn/direct/5e37553b9868467dbea02de03ec3d398.webp#pic_center
可以看到,网关在负载均衡下的第一入口,也就是说,整个微服务系统,外部请求都必须要经过网关,可以说是整个系统的门卫了。那网关具体负责哪些呢?
https://img-blog.csdnimg.cn/direct/947c725a7bca4324bafcc64c62efb85d.webp#pic_center
总结来说,微服务的应用大概摆设在不同机房,不同地区,不同域名下。此时客户端(浏览器/手机/软件工具)想要请求对应的服务,都需要知道机器的具体 IP 或者域名 URL,当微服务实例众多时,这是非常难以影象的,对 于客户端来说也太复杂难以维护。
此时就有了网关,客户端相关的请求直接发送到网关,由网关根据请求标识解析判断出具体的微服务地址,再把请求转发到微服务实例。这此中的影象功能就全部交由网关来利用了。
网关选型

Cloud 全家桶中有个很重要的组件就是网关,在 1.x 版本中都是采用的 Zuul 网关;但在 2.x 版本中,Zuul 的升级不停跳票,SpringCloud 末了本身研发了一个网关 SpringCloud Gateway 替代 Zuul。所以新项目,我们就别再去用 Zuul 了,简历上也最好以 Gateway 为主。
所以如今用的主流的网关就是 SpringCloud Gateway 替代 Zuul 1.x 版网关。PmHub 中采用的也是自建 SpringCloud Gateway 的方式。
Spring Cloud Gateway

Spring Cloud Gateway是基于 Spring 生态系统之上构建的 API 网关,包括:Spring 5.x,Spring Boot 2.x 和 Project Reactor。Spring Cloud Gateway 旨在提供一种简单而有效的方法来路由到 API,并为它们提供跨领域的关注点,例如:安全性,监视/指标,限流等。
以下是官方原理图:
https://img-blog.csdnimg.cn/direct/24f293e544b84596815b29432941732f.webp#pic_center
Gateway 三大焦点

看官网先容可知,Spring Cloud Gateway 三大焦点组件分别是路由(Route)、断言(Predicate)、过滤器(Filter),构成了网关的必要功能。
https://img-blog.csdnimg.cn/direct/e81aa7373b854df9b65eb4f85ab483a4.webp#pic_center
web 前端请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,举行一些精致化控制。
predicate就是我们的匹配条件。
filter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了。
https://img-blog.csdnimg.cn/direct/c8d213037ceb43bb8c0c909fa4f56f0b.webp#pic_center
路由(Route)

路由是构建网关的根本模块,它由 ID,目标 URI,一系列的断言和过滤器构成,假如断言为 true 则匹配该路由。
在 PmHub 中网关的路由配置如下:
spring:
cloud:
    gateway:
      discovery:
      locator:
          lowerCaseServiceId: true
          enabled: true
      routes:
      # 认证中心
      - id: pmhub-auth
          uri: lb://pmhub-auth
          predicates:
            - Path=/auth/**
          filters:
            # 验证码处理
            - CacheRequestFilter
         # - ValidateCodeFilter
            - StripPrefix=1
      # 代码生成
      - id: pmhub-gen
          uri: lb://pmhub-gen
          predicates:
            - Path=/gen/**
          filters:
            - StripPrefix=0
拿认证中心折务来说,id 取的就是 auth 在 nacos 注册的服务名,如许,请求网关的 URL 中带有「/auth/**」的请求都会被转发到认证中心这个服务上来。
在spring cloud gateway中配置uri有三种方式,包括
websocket配置方式

spring:
cloud:
    gateway:
      routes:
      - id: pmhub-api
          uri: ws://localhost:9090/
          predicates:
            - Path=/api/**
http地址配置方式

spring:
cloud:
    gateway:
      routes:
      - id: pmhub-api
          uri: http://localhost:9090/
          predicates:
            - Path=/api/**
注册中心配置方式

此中 PmHub 中采用的是这种通过 Nacos 配置中心的配置方式。
spring:
cloud:
    gateway:
      routes:
      - id: pmhub-api
          uri: lb://ruoyi-api
          predicates:
            - Path=/api/**
断言(Predicate)

断言可以理解为是匹配规则,好比在 PmHub 中配置的「 - Path=/auth/**」就代表所有符合这个路径的规则都会被转发到对应的服务上面来。可以看下官网先容:
https://img-blog.csdnimg.cn/direct/1402c2c25352435a921416d9fd809c3a.webp#pic_center
简而言之,Predicate 就是为了实现一组匹配规则,让请求过来找到对应的Route 举行处置惩罚。
Spring Cloud Gateway 创建 Route 对象时, 利用RoutePredicateFactory 创建 Predicate 对象,Predicate 对象可以赋值给Route。


[*]Spring Cloud Gateway包罗许多内置的Route Predicate Factories。
[*]所有这些断言都匹配 HTTP 请求的不同属性。
[*]多个Route Predicate Factories可以通过逻辑与(and)结合起来一起利用。
路由断言工厂 RoutePredicateFactory 包罗的主要实现类如图所示,包括Datetime、请求的远端地址、路由权重、请求头、Host 地址、请求方法、请求路径和请求参数等范例的路由断言。
https://img-blog.csdnimg.cn/direct/f035e5a0d57946efae3c5f397db7137c.webp#pic_center
当然了除了我们界说的规则,也是可以支持一下路由规则的自界说的,以下是一些常用的断言。
Weight-匹配权重

spring:
application:
    name: pmhub-gateway
cloud:
    gateway:
      routes:
      - id: pmhub-system-a
          uri: http://localhost:9201/
          predicates:
            - Weight=group1, 8
      - id: pmhub-system-b
          uri: http://localhost:9201/
          predicates:
            - Weight=group1, 2
Datetime-匹配日期时间之后发生的请求

spring:
application:
    name: pmhub-gateway
cloud:
    gateway:
      routes:
      - id: pmhub-system
          uri: http://localhost:9201/
          predicates:
            - After=2021-02-23T14:20:00.000+08:00
Query-匹配查询参数

spring:
application:
    name: pmhub-gateway
cloud:
    gateway:
      routes:
      - id: pmhub-system
          uri: http://localhost:9201/
          predicates:
            - Query=username, abc.
Path-匹配请求路径

spring:
application:
    name: pmhub-gateway
cloud:
    gateway:
      routes:
      - id: pmhub-system
          uri: http://localhost:9201/
          predicates:
            - Path=/system/**
Header-匹配具有指定名称的请求头,

\d+值匹配正则表达式
spring:
application:
    name: pmhub-gateway
cloud:
    gateway:
      routes:
      - id: pmhub-system
          uri: http://localhost:9201/
          predicates:
            - Header=X-Request-Id, \d+
当然了,内置的模板不满意需求,也是可以自界说断言规则的,方法也比力简单,按照以下套路即可:


[*]要么继承 AbstractRoutePredicateFactory 抽象类
[*]要么实现 lRoutePredicateFactory:接口
[*]类开头任意取名,但是必须以 RoutePredicateFactory 后缀末端
如下代码:
/**
* @auther canghe
* @create 2024-05-23 18:30
*/
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{
    public MyRoutePredicateFactory()
    {
      super(MyRoutePredicateFactory.Config.class);
    }

    @Validated
    public static class Config{
      @Setter
      @Getter
      @NotEmpty
      private String userType; //钻、金、银等用户等级
    }

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config)
    {
      return new Predicate<ServerWebExchange>()
      {
            @Override
            public boolean test(ServerWebExchange serverWebExchange)
            {
                //检查request的参数里面,userType是否为指定的值,符合配置就通过
                String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");

                if (userType == null) return false;

                //如果说参数存在,就和config的数据进行比较
                if(userType.equals(config.getUserType())) {
                  return true;
                }

                return false;
            }
      };
    }
}

过滤器(Filter)

网关中的过滤器,有点类似 SpringMVC 里面的拦截器 Interceptor 以及 Servlet 的过滤器,此中「pre」 和「post」分别会在请求被执行钱调用和被执行后调用,用来修改请求和相应信息。
过滤器也是口试中最常问的知识点,好比记录接口调用市场统计、限流、黑白名单等。
因文章篇幅有限,将在下一章单独细说细说,可见其重要程度了,也是 PmHub 项目框架的焦点之一了。感兴趣可以连续关注。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 微服务网关Gateway(上)