• 微服务·架构组件之网关- Spring Cloud Gateway


    微服务·架构组件之网关- Spring Cloud Gateway

    引言

    微服务架构已成为构建现代化应用程序的关键范式之一,它将应用程序拆分成多个小型、可独立部署的服务。Spring Cloud Gateway是Spring Cloud生态系统中的一个关键组件,用于构建和管理微服务架构中的网关。本报告旨在调查和介绍Spring Cloud Gateway的核心概念、架构、功能以及其在微服务架构中的作用。

    概述

    Spring Cloud Gateway 是 Spring 官方基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,旨在为微服务架构提供一种简单而有效的统一的 API 路由管理方式,统一访问接口。Spring Cloud Gateway 作为 Spring Cloud 生态系中的网关,目标是替代 Netflix ZUUL,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。它是基于Nttey的响应式开发模式。

    核心概念

    请添加图片描述
    路由(Route):路由是网关最基础的部分,路由信息由一个ID、一个目标的URL、一组断言工程和一组过滤器组成。如果断言为真,则说明请求URL和配置的路由匹配。

    断言(Predicates):Java8中的断言函数,Spring Cloud Gateway中的断言函数允许开发者去定义函数匹配来自Http Request中的任何信息,比如请求头和参数等。

    过滤器(Filter):一个标准的Spring webFilter, 可以分为Gateway Filter和Global Filter。过滤器Filter可以对请求和响应进行处理。

    示例:

    server:
    	port: 8080
    spring:
    	application:
    		name: api-gateway
    	cloud:
    		gateway:
    			routes:
    			- 	id: product-service
    				uri:http://127.0.0.1:9002
    				predicates:
    				-	Path=/product/**
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • id:自定义的路由Id,保持唯一。
    • uri:目标服务地址
    • predicates:路由条件,Predicate接受一个输入参数,返回一个boolean结果。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑,比如:与、或、非
    • filters:过滤规则。

    工作流程

    请添加图片描述

    • 客户端将请求发送到Spring Cloud Gateway上。
    • Spring Cloud Gateway通过Gateway Handler Mapping找到与请求相匹配的路由,并将其发送给Gateway Web Handler。
    • Gateway Web Handler 通过指定的过滤器链(Filter Chain)将请求转发到实际的服务节点中,执行业务逻辑,返回响应结果。
    • 过滤器可能会在转发请求之前(pre)或之后(post)执行业务逻辑。
    • 过滤器可以在请求转发到服务端前,对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等。
    • 过滤器可以在响应返回客户端之前,对响应进行拦截和再处理,例如修改响应内容或响应头、日志输出、流量监控等。

    路由规则

    在这里插入图片描述

    动态路由

    动态路由,即自动从注册中心获取服务列表并访问。
    现在以spring cloud gateway 集成nacos为例

    1. 添加依赖:在项目的’pom.xml’文件中添加Spring cloud gateway和nacos的相关依赖
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-gatewayartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. 配置文件:在’application.properties’或’application.yml’中配置Nacos注册中心的地址以及网关的路由规则
    spring:
      application:
        name: gateway-service
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 
        gateway:
          discovery:
            locator:
              enabled: true # 启用服务发现
          routes:
            - id: service-route
              uri: lb://service-name # 后端服务名称
              predicates:
                - Path=/service-path/** # 匹配的请求路径
              filters:
                - StripPrefix=1 # 去掉前缀
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    1. 启动服务发现:在Spring Boot应用程序的主类上使用’@EnableDiscoveryClient’注解,以启用服务发现功能。
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class GatewayServiceApplication {
        public static void main(String[] args) {
            SpringApplication.run(GatewayServiceApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    重写转发路径

    在Spring Cloud gateway中,路由转发是直接将匹配的路由path直接拼接到映射路径(URL)之后,那么在微服务中开发往往没有那么便利,这里可以通过RewritePath机制来进行路径重写。

    spring:
      application:
        name: gateway-service
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 
        gateway:
          discovery:
            locator:
              enabled: true # 启用服务发现
          routes:
            - id: service-route
              uri: lb://service-name # 后端服务名称
              predicates:
                - Path=/service-path/** # 匹配的请求路径
              filters:
                - RewritePath=/serive-path/(? >.*), /$\{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    过滤器

    Spring Cloud Gateway的Filter从作用范围可分为两种:GatewayFilter与GlobalFilter

    • GatewayFilter:应用到单个路由或者一个分组的路由上。
    • GlobalFilter:应用到所有的路由上。

    局部过滤器(GatewayFilter)

    局部过滤器是针对单个路由的过滤器,可以对访问的URL过滤,进行切面处理。常见的局部过滤器:

    • AddRequestHeader,为原始请求添加Header。
    • Hystrix:为路由引入Hystrix的断路器保护。
    • FallbackHeaders:为fallbackUri的请求头中添加具体的异常信息。
    • RequestRateLiiter:对于请求限流,限流算法为令牌桶算法。

    全局过滤器(GlobalFilter)

    全局过滤器作用于所有路由,Spring Cloud Gateway定义了GlobalFilter接口,用户可以自定义实现自己的Global Filter。通过全局过滤器可以实现对权限的统一检验,安全性验证等功能。
    在这里插入图片描述

    高级应用

    鉴权

    在这里插入图片描述
    角色:

    • 客户端:访问微服务资源
    • 网关:负责转发、认证、鉴权
    • OAuth2.0授权服务:负责认证授权颁发令牌
    • 微服务集合:提供资源

    流程:

    • 客户端发送请求给网关获取令牌
    • 网关收到请求,直接转发给授权服务
    • 授权服务验证用户名、密码等,验证通过颁发令牌给客户端
    • 客户端携带令牌请求资源,请求直接到网关层
    • 网关层对令牌及性能校验、鉴权和访问资源所需的权限进行比较。如果权限有交集则通过校验,直接转发给微服务
    • 微服务处理逻辑

    网关限流

    常见的限流算法

    • 计数器法
      一般我们会限制一秒钟能够通过的请求数,比如限流的qps为100,算法的实现思路就从从第一请求进来开始,在接下来的1s内,每来一个请求,就把计数加1,如果累加的数字达到100,那么或许的请求就会被全部拒绝。等到1s结束后,计数器恢复成0,重新开始计数。
    • 漏斗算法
      匀速处理请求。不管调用方多么不稳定,通过漏斗算法进行限流,每10ms处理一次请求,因为处理的速度是固定的,请求进来的速度是未知的,可能突然进来很多请求,没来得及处理请求就先放到桶里。如果桶满了,那么新进来的请求就丢弃。
    • 令牌桶算法
      令牌桶算法是对漏斗算法的一个改进,存在一个桶,用来存放固定数量的令牌,然后以一定的速率往桶中放令牌。每次请求进来的时候需要先获取令牌,只有拿到令牌才有机会继续执行,否则选择等待可用的令牌或者直接拒绝。
    • Gateway令牌桶
      Spring Cloud Gateway 官方提供了RequestRateLimiterGatewayFilterFactory类,使用redis和lua脚本实现了令牌桶的方式。

    实现步骤

    • 引入依赖
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-data-redis-reactiveartifactId>
        <version>2.2.10.RELEASEversion>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 创建限流标示
      限流通常要根据某个参数值作为参考依据来进行线路的,例如每个IP只能只能访问2次,创建根据IP限流的对象,该对象需要实现KeyResolver接口
    public class IpKeyResolver implements KeyResolver {
    
        /***
         * 根据IP限流
         * @param exchange
         * @return
         */
        @Override
        public Mono<String> resolve(ServerWebExchange exchange) {
            return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    需要将IpKeyResolver的实例交给Spring容器管理。

    @Configuration
    public class GatewayRateLimitConfig {
    
    @Bean("ipKeyResolver")
    public KeyResolver userIpKeyResolver(){
    	return new IpKeyResolver();
    }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 配置限流速率
    spring:
    	cloud:
            gateway:
              routes:
                #商品服务
                - id: goods_route
                  uri: lb://mall-goods
                  predicates:
                    - Path=/mall/brand/**
                  filters:
                    - StripPrefix=1
                    # 指定过滤器
                    - name: RequestRateLimiter
                      args:
                        # 指定限流标识
                        key-resolver: '#{@ipKeyResolver}'
                        # 速率限流
                        redis-rate-limiter.replenishRate: 1
                        # 能容纳的并发流量总数
                        redis-rate-limiter.burstCapacity: 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    监控

    监控每个请求的响应参数是否包含手机号码
    首先,您需要创建一个自定义过滤器类,该类将检查响应参数中是否包含手机号码。这可以通过解析响应内容并搜索手机号码的正则表达式来完成。下面是一个示例:

    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    @Component
    @Order(1) // 设置过滤器顺序
    public class PhoneNumberCheckFilter implements GlobalFilter {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            // 检查响应内容是否包含手机号码的逻辑
            // 解析响应内容并搜索手机号码的正则表达式
            // 如果包含手机号码,则可以进行相关处理,例如记录日志或触发警报
            // 这里仅提供示例框架,具体实现需要根据需求编写
            return chain.filter(exchange);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    然后配置过滤器

    spring:
      cloud:
        gateway:
          routes:
            - id: route-name
              uri: http://example.com
              filters:
                - PhoneNumberCheck= # 这里填写自定义过滤器的名字
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    理解React页面渲染原理,如何优化React性能?
    手写raft(一) 实现leader选举
    【Hack The Box】linux练习-- Doctor
    mybatis实战:二、mybatis xml 方式的基本用法
    C++Qt开发——阻止系统休眠方法
    Flutter自动路由插件auto_route详解
    【软件测试】采用等价类划分法设计测试用例
    用C语言写个控制台扫雷游戏(附完整代码)
    访问控制列表配置实验
    数据结构七:七大排序(插入排序,希尔排序,选择排序,堆排序冒泡排序,快速排序,归并排序)
  • 原文地址:https://blog.csdn.net/baidu_41934937/article/details/132719492