06、SpringCloud 系列:Gateway - 网关

SpringCloud 系列列表:

文章名文章地址
01、Eureka - 集群、服务发现https://blog.csdn.net/qq_46023503/article/details/128319023
02、Ribbon - 负载均衡https://blog.csdn.net/qq_46023503/article/details/128332288
03、OpenFeign - 远程调用https://blog.csdn.net/qq_46023503/article/details/128387961
04、Hystrix - 断路器https://blog.csdn.net/qq_46023503/article/details/128408601
05、Sleuth - 链路追踪https://blog.csdn.net/qq_46023503/article/details/128409339
06、Gateway - 网关https://blog.csdn.net/qq_46023503/article/details/128430842
07、Alibaba - 介绍https://blog.csdn.net/qq_46023503/article/details/128434080
08、Nacos - 安装、启动https://blog.csdn.net/qq_46023503/article/details/128460411
09、Nacos - 配置文件中心https://blog.csdn.net/qq_46023503/article/details/128460649
10、Nacos - 注册中心https://blog.csdn.net/qq_46023503/article/details/128460494

1 网关概述

网关是微服务最边缘的服务,直接暴露给用户,用来做用户和微服务的桥梁
在这里插入图片描述

  • 没有网关:客户端直接访问微服务,会需要在客户端配置很多的 ip:port,如果 user-service 并发比较大,则无法完成负载均衡
  • 有网关:客户端访问网关,网关来访问微服务,(网关可以和注册中心整合,通过服务名称找到目标的 ip:prot)这样只需要使用服务名称即可访问微服务,可以实现负载均衡,可以实现 token 拦截,权限验证,限流等操作

2 Spring Cloud Gateway 简介

  • 它是 Spring Cloud 官方提供的用来取代 zuul(netflix)的新一代网关组件
  • zuul:1.0 , 2.0 ,zuul 的本质,一组过滤器,根据自定义的过滤器顺序来执行,本质就是 web 组件,web 三大组件(监听器 过滤器 servlet) 拦截 springmvc
  • zuul1.0 使用的是 BIO(Blocking IO),tomcat7.0 以前都是 BIO,性能一般 zuul2.0 性能好,NIO
  • 它的目地是让路由更加简单,灵活,还提供了一些强大的过滤器功能,例如:熔断、限流、重 试,自义定过滤器等 token 校验 ip 黑名单等 SpringCloud Gateway作为Spring Cloud生态的网关,目标是替代Zuul,在SpringCloud2.0 以上的版本中,没有对新版本的 zuul2.0 以上的最新高性能版本进行集成,仍然还是使用的 zuul1.x[可以看项目依赖找到]非 Reactor 模式的老版本。而为了提升网关的性能, SpringCloud Gateway 是基于 webFlux 框架实现的,而 webFlux 框架底层则使用了高性能 的 Reactor 模式通信框架的 Netty NIO(非阻塞式 io) BIO

3 特征

在这里插入图片描述

4 Spring Cloud Gateway 工作流程

在这里插入图片描述

  • 客户端向 springcloud Gateway 发出请求,然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。 Handler 再通过指定的过滤器来将请求发送到实际的服务的业务逻辑,然后返回
  • 过滤器之间用虚线分开是因为过滤器可能会在发送请求之前【pre】或之后【post】执行业务逻辑,对其进行加强或处理
  • Filter 在 【pre】 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转 换等;在【post】 类型的过滤器中可以做响应内容、响应头的修改、日志的输出,流量监控等有着 非常重要的作用
  • 总结:Gateway 的核心逻辑也就是路由转发 + 执行过滤器链

5 Spring Cloud Gateway 三大核心概念

5.1 Route(路由)(重点)

和 eureka 结合做动态路由,路由信息的组成: 由一个 ID、一个目的 URL、一组断言工厂、一组 Filter 组成。 如果路由断言为真,说明请求 URL 和配置路由匹配

5.2 Predicate(断言)

就是一个返回 bool 的表达式,Java 8 中的断言函数。 lambda 四大接口:供给形,消费性,函数型,断言型。Spring Cloud Gateway 中的断言函数输入类型 是 Spring 5.0 框架中的 ServerWebExchange。Spring Cloud Gateway 的断言函数允许开发者去定义匹配来自于 Http Request 中的任何信息比如请求头和参数

5.3 Filter(过滤) (重点)

一个标准的 Spring WebFilter。 Web 三大组件、(servlet listener filter) mvc interceptor。Spring Cloud Gateway 中的 Filter 分为两种类型的 Filter,分别是 Gateway Filter 和 Global Filter。过滤器 Filter 将会对请求和响应进行修改处理。 一个是针对某一个路由(路径)的 filter 对某一个接口做限流,一个是针对全局的 filter

6 Nginx 和 Gateway 的区别

  • Nginx 在做路由,负载均衡,限流之前,都有修改 nginx.conf 的配置文件,把需要负载均衡,路由,限流的规则加在里面。Eg:使用 nginx 做 tomcat 的负载均衡
  • 但是 gateway 不同,gateway 自动的负载均衡和路由,gateway 和 eureka 高度集成,实现自动的路由,和 Ribbon 结合,实现了负载均衡(lb),gateway 也能轻易的实现限流和权限验证
  • Nginx(c)比 gateway(java)的性能高一点
  • Nginx 是更大的,服务器级别的;Gateway 是项目级别的
    在这里插入图片描述

7 Gateway 快速入门

7.1 本次访问流程

在这里插入图片描述

7.2 实现步骤

1、创建 user-service 项目

  • 只选择一个 spring web 依赖
  • 在 yml 文件中配置端口为 8081
  • 创建控制层方便测试
@RestController
public class LoginController {
    @GetMapping("/login")
    public String login(){
        return "登陆成功!";
    }
}

2、创建 gateway 项目

  • 只选择 gateway 依赖(此依赖使用 jetty 服务器,而 web 使用的是 tomcat)
  • 修改 springboot 版本号为 2.3.12.RELEASE,修改 springcloud 版本号为 Hoxton.SR12
  • yml 文件中配置
server:
  port: 80
spring:
  application:
    name: gateway80
  cloud:
    gateway:
      enabled: true #开启网关,默认是开启的
      routes: #设置路由,注意是数组,可以设置多个,按照 id 做隔离
        - id: login #路由 id,没有要求,保持唯一即可
          uri: http://localhost:8081 #设置真正的服务 ip:port
          predicates: #断言匹配
            - Path=/login #和服务中的路径匹配,是正则匹配的模式,匹配成功就会访问到指定的uri下面
        - id: provider-service-router
          uri: http://localhost:8082
          predicates:
            - Path=/info/** #如果匹配到第一个路由,则第二个就不会走了,注意这不是负载均衡

3、启动项目测试
访问 localhost:8081/login 和 loclhost:80/login 都可以访问到 user-service 中的控制层方法

8 Gateway 集群

基础服务设施 (eureka,gateway configserver auth-server) 这里使用虚拟机实现
在这里插入图片描述
1、创建两个 gateway,端口分别为 80 和 81

2、Nginx 的配置文件修改
在这里插入图片描述
3、访问测试

9 Gateway 微服务名动态路由,负载均衡

9.1 概述

  • 从之前的配置里面可以看到 URL 都是写死的,这不符合微服务的要求,微服务是只要知道服务的名字,根据名字去找,而直接写死就没有负载均衡的效果了
  • 默认情况下 Gateway 会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
  • 需要注意的是 uri 的协议为 lb(load Balance),表示启用 Gateway 的负载均衡功能。lb://serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri 协议:就是双方约定的一个接头暗号

9.2 案例

springboot 版本为 2.3.12.RELEASE,springcloud 版本为 Hoxton.SR12

1、创建一个 eureka 服务端
参考 eureka

2、创建 user-service 服务

  • 选择依赖 eureka-client、spring-web
  • 启动类上添加上 @EnableEurekaClient
  • yml 文件
server:
  port: 8081
spring:
  application: #服务名字
    name: gatewayuserservice
eureka:
  client:
    service-url: #注册到 eureka 服务器端
      defaultZone: http://localhost:8761/eureka
  • 控制层测试方法
@RestController
public class LoginController {
    @GetMapping("/login")
    public String login(){
        return "登陆成功!";
    }
}

3、创建 gateway 服务

  • 选择依赖 gateway、eureka-client
  • 启动类上添加上 @EnableEurekaClient
  • yml 文件
server:
  port: 80
spring:
  application:
    name: gateway80
  cloud:
    gateway:
      enabled: true
      routes: #可以不写
        - id: login
          uri: lb://gatewayuserservice #使用 lb 协议 微服务名称做负均
          predicates:
            - Path=/login
      discovery:
        locator:
          enabled: true #开启动态路由
          lower-case-service-id: true #动态路由小驼峰规则
eureka:
  client:
    service-url: # 注册到 eureka 服务上
      defaultZone: http://localhost:8761/eureka

4、测试
访问 localhost:8081/login、localhost:80/login、localhost:80/gatewayuserservice/login 都可以访问到 user-service 中控制层的方法

10 Filter 过滤器工厂

10.1 概述

gateway 里面的过滤器和 Servlet 里面的过滤器,功能差不多,路由过滤器可以用于修改进入 Http 请求和返回 Http 响应

10.2 分类

按生命周期分两种

  • pre:在业务逻辑之前
  • post:在业务逻辑之后

按种类分也是两种

  • GatewayFilter:需要配置某个路由,才能过滤。如果需要使用全局路由,需要配置 DefaultFilters
  • GlobalFilter:全局过滤器,不需要配置路由,系统初始化作用到所有路由上

10.3 自定义网关过滤器(重点)

自定义全局过滤器
全局过滤器的优点的初始化时默认挂到所有路由上,可以使用它来完成 IP 过滤,限流等功能

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        System.out.println("--------------------------进入了我自定义的拦截器");
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (token==null){
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//返回错误状态码
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);//放行
    }

    //order 越小,越先执行
    @Override
    public int getOrder() {
        return 0;
    }
}

访问测试:http://localhost/gatewayuserservice/login?token=1

11 限流

11.1 什么是限流

通俗的说,限流就是限制一段时间内,用户访问资源的次数,减轻服务器压力,限流大致分为两种

  • IP 限流(5s 内同一个 ip 访问超过 3 次,则限制不让访问,过一段时间才可继续访问)
  • 请求量限流(只要在一段时间内(窗口期),请求次数达到阀值,就直接拒绝后面来的访问了, 过一段时间才可以继续访问)(粒度可以细化到一个api(url),一个服务)

11.2 本次限流模型

限流模型:漏斗算法 ,令牌桶算法,窗口滑动算法 计数器算法
在这里插入图片描述

  • 所有的请求在处理之前都需要拿到一个可用的令牌才会被处理
  • 根据限流大小,设置按照一定的速率往桶里添加令牌
  • 桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝
  • 请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除
  • 令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流

11.3 Gateway 结合 Redis 实现请求量限流

Spring Cloud Gateway 已经内置了一个 RequestRateLimiterGatewayFilterFactory,可以直接使用。 目前 RequestRateLimiterGatewayFilterFactory 的实现依赖于 Redis,所以要引入 spring-boot-starter-data-redis-reactive

在前面项目的基础上
1、添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2、修改 yml 文件

server:
  port: 80
spring:
  application:
    name: gateway80
  cloud:
    gateway:
      enabled: true
      routes:
        - id: login
          uri: lb://gatewayuserservice
          predicates:
            - Path=/login
          filters: #限流的设定
            - name: RequestRateLimiter #名字固定
              args:
                key-resolver: '#{@hostAddrKeyResolver}' #里面的名字必须和配置类的 bean 名字一样
                redis-rate-limiter.replenishRate: 1 # 每秒钟产生的令牌数
                redis-rate-limiter.burstCapacity: 3 # 令牌的最大数量
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
  redis: #redis 的配置
    host: 127.0.0.1
    port: 6379
    database: 0
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

3、创建配置类

@Configuration
public class RequestRateLimiterConfig {
    /**
     * IP 限流
     * 把用户的 IP 作为限流的 Key
     */
    @Bean
    @Primary
    public KeyResolver hostAddrKeyResolver() {
        return (exchange) -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
    /**
     * 用户 id 限流
     * 把用户 ID 作为限流的 key
     */
    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
    }
    /**
     * 请求接口限流
     * 把请求的路径作为限流 key
     */
    @Bean
    public KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }
}

4、访问测试
快速访问多次,出现 429 状态码

12 跨域配置

因为网关是微服务的边缘 所有的请求都要走网关 跨域的配置只需要写在网关即可

12.1 配置类配置

@Configuration
public class CorsConfig { 
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
   }
}

12.2 yml 文件配置

spring:
 cloud:
  gateway:
   globalcors:
    corsConfigurations:
     '[/**]': // 针对哪些路径
     allowCredentials: true // 这个是可以携带 cookie
     allowedHeaders: '*'
     allowedMethods: '*'
     allowedOrigins: '*'
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玄天灵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值