【SpringCloud(6)】Gateway路由网关;zuul路由;gateway实现原理和架构概念;gateway工作流程;静态转发配置

1. 认识Gateway

1.1 zuul路由网关和Gateway网关的由来

Zuul是Netflix开源的微服务网关,可以和Eureka、Ribbon、Hystrix等组件配合使用,Spring Cloud对Zuul进行了整合与增强,Zuul的主要功能是路由转发和过滤器。路由转发功能是将外部请求转发到具体的我们的微服务上,是实现外部访问统一入口的基础,因为之后我们所有访问都要从网关走,我们会通过配置忽略掉其他的访问。而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。

但随着zuul的年龄越来越大,一些功能已经追不上时代的步伐了所以Netflix打算升级zuul开发zuul2,但是由于zuul的核心开发人员跳槽,在升级zuul2上开发组又有写分歧,所以导致zuul2网关框架一直跳票。

因为zuul2迟迟不来,spring社区再也等不了了,所以自己开发了一套全新的微服务网关------GetWay

1.2 Gateway 网关

Gateway是在Spring生态系统之上构建的API网关服务,基于Spring5,SpringBoot2和project Reactor等技术

Getway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等。

其底层使用了Netty通讯框架

那么Gateway所处的理论位置在哪呢?

1.3 为什么选择 GateWay?

一方面因为Zuul1.0已经进入了维护阶段,而且GateWay是SpringCloud团队研发的,是请儿子产品,值得信赖。很多功能Zuul都没有用起来也飞车的简单便捷

Gateway是基于异步非阻塞模型上进行开发的,性能方面不需要单项。

虽然Netlix早就发布了最小的Zuul2.x,但SpringCloud貌似没有整合计划。而且Netflix相关的组件都宣布进入维护期,不知前景如何。

  • 1.4 SpringCloud GateWay 具有如下的特性:
    1. 动态路由:能够匹配任何请求属性
    2. 可以对路由指定Predicate(断言)和 Filter(过滤器)
    3. 集成Hystrix的断路器功能;
    4. 集成SpringCloud服务发现功能
    5. 易于编写Predicate(断言)和 Filter(过滤器)
    6. 请求限流功能
    7. 支持路径重写

1.4 GateWay和Zuul的区别

在SpringCloud Finchly正式版之前,SpringCloud推荐的网关是Netflix的zuul

  1. Zuul 1.x,是一个基于阻塞I/O的API Gateway
  2. zuul 1.x 基于Servlet 2.5使用阻塞架构,它不支持长连接(瑞WebSocket)Zuul的设计模式和Nginx较像,每次I/O操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx用C++实现,Zuul用Java实现,而JVM本身会有第一次加载较慢的情况,使得Zuul的性能相对较差
  3. Zuul 2.x 的理念更先进,想基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合。Zuul 2.x 的性能较Zuul 1.x 有较大提示。在性能方面,根据官方提供的基准测试,SpringCloud Gateway的RPS(每秒请求数)是Zuul的1.6倍
  4. SpringCloud Gateway建立在Spring5、project Reactor和SpringBoot2之上,使用非阻塞API
  5. SPringCloud Gateway还支持WebSocket,并且与Spring紧密集成拥有更好的开发体验

1.5 Zuul 1.x 模型

SpringCloud中所集成的Zuul版本,采用的是Tomcat容器,使用的是传统的Servlet IO处理器

Servlet是一个简单的网络IO模型,当请求进入Servlet container时,Servelt Container就会为其绑定一个线程,在并发不高的场景下这种模型是适用的,但是一旦高并发,线程数量就会上涨,而线程资源代价是昂贵的,严重影响请求的处理时间。

在一些简单业务场景下,不希望为每个request分配一个线程,只需要1个或几个线程就能应对极大并发请求,这种业务场景下Servlet模型没有优势

所以Zuul 1.x是基于Servlet之上的一个阻塞式处理模型,即Spring实现了处理所有的request请求的一个servlet,并由该Servelt阻塞式处理。所以SpringCloud Zuul无法摆脱Servlet模型的弊端。

2. Gateway 的相关概念

  • Route(路由)
    • 路由是构建网关的基本模块,它由ID、目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
  • Predicate(断言)
    • 开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求和断言相匹配则进行路由
  • Filter(过滤)
    • 指的是Spring框架中GatwayFilter的实例,使用过滤器,可以在请求被路由前后对请求进行修改

3. Gateway的工作流量

  • 核心逻辑:路由转发 + 执行过滤器链

客户端向SpringCloud Gateway发出请求。然后再Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway Web Handler

Handler再通过指定的过滤器链来讲请求我们实际的业务执行业务逻辑,然后返回

过滤器之间用虚线分开是因为过滤器可能会在发送代理之前(pre)或之后(post)执行业务逻辑

Filter在 pre 类型的顾虑其可以做参数校验、权限校验、流量监控、日志输出、协议转换

在 post 类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用

4. Gateway 实现

4.1 静态转发地址

首先需要添加gateway的jar包

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

当使用gateway时,SpringCloud的web和auctor 这两个jar包就不需要了

4.1.1 yaml配置转发

yaml 复制代码
server:
  port: 9527
spring:
  application:
    name: cloud-gateway-service
  cloud:
    gateway:
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

4.1.2 Config配置转发(设置pre 断言)

java 复制代码
@Configuration
public class GateWayConfig {

    /**
     * 配置一个id为route-name的路由规则
     * 当范围跟地址hhtp://localhost:9527/guonei时就会自动转发到地址 http://news.baidu.com/guonei
     * @param routeLocatorBuilder
     * @return
     */
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder)
    {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();

        routes.route("path_route_atguigu",
                r -> r.path("/guonei") 
                        .uri("http://news.baidu.com/guonei")).build();

        return routes.build();
    }
}

4.2 微服务名称转发

在yaml中,开启discovery.locator.enabled就可以用微服务名称的方式来进行转发

yaml 复制代码
spring:
  application:
    name: cloud-gateway-service
  cloud:
    gateway:

      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务进行路由

      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://CLOUD-PAYMENT-SERVICE # 微服务名称
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://CLOUD-PAYMENT-SERVICE # 微服务名称
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
#            - After=2023-03-16T15:26:01.338+08:00[Asia/Shanghai] # 在这个时间之后的请求才可以被网关转发
#            - Cookie=username,zzyy # 只能指定用户名称的请求才可以转发

我们的uri直接写微服务名称就可以了 lb://CLOUD-PAYMENT-SERVICE

lb:// *********** 加上lb是为了开启负载均衡策略

4.3 过滤器

添加一个实现类,实现 GlobalFilter, Ordered 接口

java 复制代码
/**
 * GateWay的全局过滤器
 */
@Component
public class MyLogGateWayFilter implements GlobalFilter, Ordered {

    /**
     *
     * @param exchange ------------ 请求对象
     * @param chain ------------ 控制请求的过滤器
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("____________________MyLogGateWayFilter"+new Date().toString());
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if (uname == null){
            System.out.println("用户名为null -------------- 非法用户");
            exchange.getResponse().setRawStatusCode(HttpStatus.HTTP_NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        // 没有问题,就讲请求续传下去
        return chain.filter(exchange);
    }

    /**
     * 设置过滤器方法的权重
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
  • GlobalFilter:全局过滤器
  • Ordered:过滤器权重

🥸🏏SpringCloud微服务专栏

  1. 【SpringCloud(1)】初识微服务架构:创建一个简单的微服务;java与Spring与微服务;初入RestTemplate
  2. 【SpringCloud(2)】微服务注册中心:Eureka、Zookeeper;CAP分析;服务注册与服务发现;单机/集群部署Eureka;连接注册中心
  3. 【SpringCloud(3)】Ribbon负载均衡:IRule原理轮询算法;LB负载均衡;loadbalancer和IRule组件;Ribbon和Ngin负载均衡的区别
  4. 【SpringCloud(4)】OpenFeign客户端:OpenFeign服务绑定;调用服务接口;Feign和OpenFeign
  5. 【SpringCloud(5)】Hystrix断路器:服务雪崩概念;服务降级、服务熔断和服务限流概念;使用Hystrix完成服务降级与服务熔断

💕👉博客专栏

相关推荐
白衣鸽子4 小时前
RPO 与 RTO:分布式系统容灾的双子星
后端·架构
鹿里噜哩5 小时前
Nacos跨Group及Namespace发现服务
java·spring cloud
一个处女座的暖男程序猿5 小时前
若依微服务 nacos的配置文件
微服务·云原生·架构
ChinaRainbowSea5 小时前
11. Spring AI + ELT
java·人工智能·后端·spring·ai编程
AI新兵5 小时前
AI大事记12:Transformer 架构——重塑 NLP 的革命性技术(下)
人工智能·架构·transformer
尘世中一位迷途小书童5 小时前
代码质量保障:ESLint + Prettier + Stylelint 三剑客完美配置
前端·架构
尘世中一位迷途小书童6 小时前
从零搭建:pnpm + Turborepo 项目架构实战(含完整代码)
前端·架构
canonical_entropy6 小时前
最小信息表达:软件框架设计的第一性原理
后端·架构·编译原理
自由的疯7 小时前
Java Docker部署RuoYi框架的jar包
java·后端·架构