基于Spring Boot2.x 设置 Spring Cloud Gateway 限流(令牌桶模式)

发布时间 2023-12-31 18:16:20作者: 夏秋初

参考

注意

  1. 配置中设置限流但是不设置 key-resolver访问会直接返回 403 错误码。
  2. 限流达到阈值会返回 429 错误码。

环境

环境 版本 说明
Windows 10
VS Code 1.85.1
Spring Boot Extension Pack v0.2.1 vscode插件
Extension Pack for Java v0.25.15 vscode插件
JDK 11
Springboot 2.3.12.RELEASE
spring-cloud-dependencies Hoxton.SR12 mvn依赖
spring-cloud-starter-gateway 未设置 mvn依赖
spring-boot-starter-data-redis-reactive 未设置 mvn依赖(限流桶用到)
Apache Maven 3.8.6
Redis 7.2.3 基于docker
Docker 24.0.6
Docker Desktop 4.25.2 (129061)

正文

项目为多模块项目,其中包含网关模块(gateway)、api模块(api)和公共模块(common);网关模块将请求映射到api模块,公共模块存放公共代码。

网关模块(gateway)代码

  1. pom.xml 引入网关与 Redis 依赖。

    <!-- 限流用到 -->
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
    <!-- 网关与 spring-boot-starter-web 互斥,只能保留其一-->
    <dependency> 
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    
  2. 入口文件 gateway\src\main\java\com\xiaqiuchu\gateway\DemoApplication.java

    package com.xiaqiuchu.gateway;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.cloud.client.SpringCloudApplication;
    
    @SpringCloudApplication
    public class DemoApplication {
    	public static void main(String[] args) {
    		SpringApplication.run(DemoApplication.class, args);
    	}
    
    }
    
  3. 创建 gateway\src\main\java\com\xiaqiuchu\gateway\config\KeyResolverConfiguration.java

    package com.xiaqiuchu.gateway.config;
    
    import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import reactor.core.publisher.Mono;
    
    @Configuration
    public class KeyResolverConfiguration {
    	@Bean
    	public KeyResolver pathKeyResolver(){
    		return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
    	}
    }
    
  4. 修改配置 gateway\src\main\resources\application.properties

    server.port=8080
    
    # 网关日志
    logging.level.org.springframework.cloud.gateway: trace
    
    # 配置 https://blog.csdn.net/yuanchangliang/article/details/109579705
    # 介绍 https://blog.csdn.net/qq_38380025/article/details/102968559
    spring.cloud.gateway.routes[0].id=gateway
    spring.cloud.gateway.routes[0].uri=http://127.0.0.1:8081
    spring.cloud.gateway.routes[0].predicates[0]=Path=/student/**
    
    # 测试路由
    spring.cloud.gateway.routes[1].id=test
    spring.cloud.gateway.routes[1].uri=http://127.0.0.1:8081
    spring.cloud.gateway.routes[1].predicates[0]=Path=/index/**
    
    # 默认限流规则为 令牌桶。(限流默认关闭)
    # 应用于路由的过滤器的名称
    spring.cloud.gateway.routes[1].filters[0].name=RequestRateLimiter
    # 令牌入桶的速度为每秒n个,相当于QPS
    spring.cloud.gateway.routes[1].filters[0].args.redis-rate-limiter.replenishRate=1
    # 这里2n只是举例入桶和出桶,入桶与出桶数量按照实际情况进行设置。
    # 桶内能装2n个令牌,相当于峰值,要注意的是:第一秒从桶内能去2n个,但是第二秒只能取到n个了,因为入桶速度是每秒n个
    spring.cloud.gateway.routes[1].filters[0].args.redis-rate-limiter.burstCapacity=2
    # 每个请求需要的令牌数
    spring.cloud.gateway.routes[1].filters[0].args.redis-rate-limiter.requestedTokens=1
    # 限流的键的解析器的 Bean 对象的名字(不设置这个访问会直接403)
    spring.cloud.gateway.routes[1].filters[0].args.key-resolver=#{@pathKeyResolver}
    
    # redis配置
    spring.redis.host=127.0.0.1
    spring.redis.port=6379
    

api模块(api)模块代码

本模块是 web 模块,提供接口供 网关模块(gateway)映射,本模块端口号为 8081 。

公共模块(common)模块代码

本模块存放公共文件。

测试

设置令牌桶容量为2,每秒填充1个。
image