美文网首页Spring Cloud Gateway程序员简友广场
Spring Cloud Gateway(二、请求限流)

Spring Cloud Gateway(二、请求限流)

作者: 梅西爱骑车 | 来源:发表于2020-08-07 06:29 被阅读0次

    一、前言

    Spring Cloud Gateway 内置 RequestRateLimiterGatewayFilterFactory 提供请求限流的功能。该 Filter 是基于 Token Bucket Algorithm(令牌桶算法)实现的限流,同时搭配上 Redis 实现分布式限流

    对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。如下图所示,令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。

    令牌桶算法示意图

    二、引入依赖

    修改 [pom.xml]文件,引入相关的依赖如下:

        <dependencies>
            <!-- 引入 Spring Cloud Gateway 相关依赖,使用它作为网关,并实现对其的自动配置 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
    
            <!-- 实现对 Spring Data Redis 的自动化配置 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
    
        </dependencies>
    

    三、配置文件

    修改 [application.yaml]配置文件,增加限流 Filter 的配置项。完整配置如下:

    server:
      port: 8888
    
    spring:
      application:
        name: sc-gateway-application
    
      cloud:
        ## Spring Cloud Gateway 配置项,对应 GatewayProperties 类
        gateway:
          # 路由配置项,对应 RouteDefinition 数组
          routes:
            - id: erbadagang_rate_limiter # 路由的编号
              uri: https://www.jianshu.com/u/ea0462d5074c # 路由到的目标地址(我的简书主页地址)
              predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
                - Path=/jianshu
              filters:
                - StripPrefix=1
                - name: RequestRateLimiter
                  args:
                    redis-rate-limiter.replenishRate: 1 # 令牌桶的每秒放的数量
                    redis-rate-limiter.burstCapacity: 2 # 令牌桶的最大令牌数
                    key-resolver: "#{@ipKeyResolver}" # 获取限流 KEY 的 Bean 的名字
            - id: guo # 路由的编号
              uri: https://www.126.com # 路由的目标地址
              predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
                - Path=/*
              filters: # 过滤器,对请求进行拦截,实现自定义的功能,对应 FilterDefinition 数组
                - StripPrefix=1
    
      ##### Redis 配置项 #####
      redis:
        host: 127.0.0.1
        port: 6379
    

    ① 针对编号为 erbadagang_rate_limiter 的路由,我们在 filter 配置项,添加了限流过滤器 RequestRateLimiter,其配置参数如下:

    • redis-rate-limiter.replenishRate:令牌桶的每秒放的数量。

    • redis-rate-limiter.burstCapacity:令牌桶的最大令牌数。

      burstCapacity 参数,我们可以近似理解为是每秒最大的请求数。因此每请求一次,都会从桶里获取掉一块令牌。
      replenishRate 参数,我们可以近似理解为是每秒平均的请求数。假设在令牌桶为空的情况下,一秒最多放这么多令牌,所以最大请求书当然也是这么多。

      实际上,在令牌桶满的情况下,每秒最大的请求数是 burstCapacity + replenishRate

    • key-resolver:获取限流 KEY 的 Bean 的名字。

    spring.redis 配置项,设置使用的 Redis 的配置。

    有一点要注意,使用的 Redis 客户端需要提供 Reative 的操作,目前能够支持的是 Lettuce 和 Redisson,也就是说我们暂时不能使用 Jedis。

    四、GatewayConfig

    创建获取限流 KEY 的 Bean。代码如下:

    package com.erbadagang.springcloud.gateway.config;
    
    import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    /**
     * @description 限流 KEY 的 Bean ,通过解析请求的来源 IP 作为限流 KEY,这样我们就能实现基于 IP 的请求限流。
     * @ClassName: GatewayConfig
     * @author: 郭秀志 jbcode@126.com
     * @date: 2020/7/29 15:26
     * @Copyright:
     */
    @Configuration
    public class GatewayConfig {
    
        @Bean
        public KeyResolver ipKeyResolver() {
            return new KeyResolver() {
    
                @Override
                public Mono<String> resolve(ServerWebExchange exchange) {
                    // 获取请求的 IP
                    return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
                }
    
            };
        }
    
    }
    

    创建的 ipKeyResolver Bean 是通过解析请求的来源 IP 作为限流 KEY,这样我们就能实现基于 IP 的请求限流。

    如果说,我们想要实现基于用户的请求限流,那么我们可以创建从请求中解析用户身份的 KeyResolver Bean。也就是说,通过自定义的 KeyResolver 来实现不同粒度的请求限流。

    五、 简单测试

    1. 启动Redis
    2. 执行 GatewayApplication, 启动网关代码。
    3. 使用浏览器,连续快速访问 http://127.0.0.1:8888/jianshu 地址,将会出现被限流为空白页。

    底线


    本文源代码使用 Apache License 2.0开源许可协议。可通过git clone命令从代码的Gitee仓库地址获取代码到本地,或者直接点击链接通过浏览器方式查看源代码。

    相关文章

      网友评论

        本文标题:Spring Cloud Gateway(二、请求限流)

        本文链接:https://www.haomeiwen.com/subject/jiwhrktx.html