8.Gateway新一代网关

1,013 阅读9分钟

源码地址 https://github.com/coderTomato/mscloud_H

1. 概述

1.1 官网

上一代zuul https://github.com/Netflix/zuul/wiki

当前gateway https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/

1.2 是什么

Gateway是SpringCloud的一个全新项目,基于Spring5+SpringBoot2 和Project Reactor等技术开发的网关。Gateway旨在为微服务架构提供一种简单而有效的API路由管理方式。
SpringCloud Gateway作为Springcloud 生态系统中的网关,目标是替代zuul,在SpringCloud2.0以上版本中,没有对新版本的Zuul2.0以上最新高性能版本进行集成,仍然还是使用的Zuul1.x非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty.
SpringCloud Gateway的目标提供统一的路由方式且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。

一句话:
SpringCloud Gateway 使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架

源码架构

1.3 能干嘛

反向代理
鉴权
流量控制
熔断
日志监控

1.4 微服务架构中网关在哪里

1.5 有Zuul了怎么又出来了gateway

1.5.1 我们为什么选择Gateway
  1. neflix不靠谱,zuul2.0一直跳票,迟迟不发布
    一方面因为Zuul1.0已经进入了维护阶段,而且Gateway是SpringCloud团队研发的
    Gateway是基于异步非阻塞模型上进行开发的,性能方面不需要担心。虽然Netflix早就发布了最新的Zuul2.x,但SpringCloud貌似没有整合计划。而且Netflix相关组件都宣布进入维护期
    多方面综合考虑Gateway是很理想的网关选择

  2. SpringCloud Gateway具有如下特性
    基于SpringFramework5,Project Reactor和SpringBoot 2.0 进行构建;
    动态路由: 能够匹配任何请求属性
    可以对路由指定Predicate和Filter
    集成Hystrix的断路器功能
    集成SpringCloud服务发现功能
    易于编写的Predicate和Filter
    请求限流功能
    支持路径重写

  3. SpringCloud Gateway与Zuul的区别
    在SpringCloud Finchley正式版之前,SpringCloud推荐的网关是Netflix提供的Zuul

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

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

1.5.3 GateWay模型

Spring WebFlux 是Spring 5.0 引入的新的响应式框架,区别于SpringMVC, 它不需要依赖Servlet API,它是完全异步非阻塞的,并且基于Reactor 来实现响应式流规范

2. 三大核心概念

2.1 Route(路由)

路由是构建网关的基本模块,它由ID, 目标URI, 一系列的断言和过滤器组成,如果断言为true则匹配该路由

2.2 Predicate(断言)

开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

2.3 Filter(过滤)

指的是spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或之后对请求进行修改

3. Gateway工作流程

路由转发+执行过滤器链

4. Gateway网关配置方式

4.1 方式一 在配置文件yml中配置

4.1.1 新建Module cloud-gateway-gateway9527
4.1.2 pom文件
<dependencies>
    <!-- gateway-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!-- eureka-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- 引入自己定义的api通用包-->
    <dependency>
        <groupId>com.jd.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
    <!-- devtools-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
4.1.3 编写yml文件
server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routch 
          uri: http://localhost:8001
          predicates:
            - Path=/payment/get/**

        - id: payment_routch2
          uri: http://localhost:8001
          predicates:
            - Path=/payment/lb/**

eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://localhost:7001/eureka
4.1.4 主启动类
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {

    public static void main(String[] args) {
        SpringApplication.run(GateWayMain9527.class, args);
    }
}
4.1.5 测试
  • 启动7001
  • 启动cloud-provider-payment8001
  • 启动9527网关
    访问说明
  • 添加网关前 http://localhost:8001/payment/get/2
  • 添加网关后 http://localhost:9527/payment/get/2

4.2 方式二 代码中注入RouteLocator的Bean

案例 通过9527网关访问到外网的百度新闻网址

新建GateWayConfig

@Configuration
public class GateWayConfig {

    /**
     * 配置了一个route-name的路由规则
     * 当访问地址http://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_routh_jd",r->r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
        return routes.build();
    }
}

成功访问到了百度新闻

5. 通过微服务名实现动态路由

默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

5.1 yml配置

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routch
          #uri: http://localhost:8001
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**

        - id: payment_routch2
          #uri: http://localhost:8001
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/lb/**

5.2 测试

  • 先启动eureka7001
  • 再启动cloud-provider-payment8001/cloud-provider-payment8002
  • 最后启动 cloud-gateway-gateway9527

访问 http://localhost:9527/payment/lb
可以实现负载均衡

6. Predicate的使用

6.1 是什么

6.2 Route Predicate Factories是什么东东

springCloudGateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。
Spring Cloud Gateway包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个RoutePredicate工厂可以进行组合
SpringCloud Gateway创建Route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给Route。Spring Cloud Gateway包含许多内置的Route Predicate Factories;
所有这些谓词都匹配HTTP请求的不同属性,多种谓词工厂可以组合,通过逻辑and

6.3 常用的Route Predicate

6.3.1 After Route Predicate
6.3.2 Before Route Predicate
6.3.3 Between Route Predicate
6.3.4 Cookie Route Predicate

带cookie访问
6.3.5 Header Route Predicate
6.3.6 Host Route Predicate
6.3.7 Method Route Predicate

GET请求才让访问,不是GET不让访问

6.3.8 Path Route Predicate
6.3.9 Query Route Predicate
6.3.10 小总结

Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理

7. Filter的使用

7.1 是什么

7.2 Spring Cloud Gateway的Filter

7.2.1生命周期 pre post
7.2.2 种类

GatewayFilter


GlobalFilter

7.3 常用的GatewayFilter

AddRequestParameter

7.4 自定义过滤器

自定义全局GlobalFilter

案例代码

@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilterOrdered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("******come in MyLogGateWayFilter: "+new Date());
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if(uname == null){
            log.info("*******用户名为null, 非法用户");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0//数字越小优先级越高
    }
}

测试

  • 先启动eureka7001
  • 再启动cloud-provider-payment8001/cloud-provider-payment8002
  • 最后启动 cloud-gateway-gateway9527
  • 访问 http://localhost:9527/payment/lb?uname=z3

加上uname才能正常访问