spring gateway RequestRateLimiter

本文详细介绍了如何在Spring Cloud Gateway中配置基于Redis的请求限流。通过设置每秒允许的请求数和最大突发请求量,实现了对特定IP地址的限流控制。深入解析了Lua脚本实现的限流算法,包括令牌桶的填充速率和容量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用spring-cloud-gateway时,可以配置请求限流;该限流基于redis实现, 用法如下

spring:
   cloud:
     gateway:
       routes:
       -  id:requestratelimiter_route
         uri:http://example.org
         filters:
         -  name:RequestRateLimiter
           args: 
             redis-rate-limiter.replenishRate:10 #允许用户每秒执行多少请求,而不会丢弃任何请求。这是令牌桶填充的速率。
            redis-rate-limiter.burstCapacity:20 #一秒钟内允许执行的最大请求数。这是令牌桶可以容纳的令牌数。将此值设置为零将阻止所有请求。
            key-resolver: "#{@userkeyResolver}" #根据关键字标识的限流
    @Bean
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(RequestUtils.getIpAddress(exchange.getRequest()));
    }

以上配置是基于请求ip做的限流配置,允许每个ip下一秒内可以有10个并请求,最多20个请求,但下一秒最多会变成10个请求;超过这个配置的请求将会被拒绝(返回409状态码)

源码分析:

源码位置在spring-cloud-gateway-core包下; 基于lua脚本实现

local tokens_key = KEYS[1]    #请求唯一标识
local timestamp_key = KEYS[2] #请求时间

local rate = tonumber(ARGV[1])     #速率,如上面例子里的 10
local capacity = tonumber(ARGV[2]) #容量,如上面例子里的 20
local now = tonumber(ARGV[3])      #当前时间 
local requested = tonumber(ARGV[4])#请求数量,默认是1

local fill_time = capacity/rate    
local ttl = math.floor(fill_time*2) #得到过期时间

local last_tokens = tonumber(redis.call("get", tokens_key)) #剩余可用令牌,没有值则为桶的容量,上面例子里值范围是 0~20
if last_tokens == nil then
  last_tokens = capacity
end

local last_refreshed = tonumber(redis.call("get", timestamp_key)) #上次请求时间,没值则为0
if last_refreshed == nil then
  last_refreshed = 0
end

local delta = math.max(0, now-last_refreshed)     #单前时间与上次请求时间的差值,最小是0;
local filled_tokens = math.min(capacity, last_tokens+(delta*rate)) #可用的令牌,最大为桶容量,范围是0~桶容量, 上面例子里是 0~20
local allowed = filled_tokens >= requested #是否允许请求, 可用令牌是否足够
local new_tokens = filled_tokens        
local allowed_num = 0
if allowed then
  new_tokens = filled_tokens - requested #可用令牌减去1
  allowed_num = 1
end

redis.call("setex", tokens_key, ttl, new_tokens) #缓存可用令牌
redis.call("setex", timestamp_key, ttl, now)     #缓存当前时间

return { allowed_num, new_tokens }

上面例子的入参情况是

转载于:https://my.oschina.net/u/782865/blog/3020566

Spring Cloud Gateway中使用`RequestRateLimiter`进行请求限流,主要涉及配置、依赖引入以及背后的限流逻辑实现。以下是一个完整的使用教程。 ### 1. 添加必要的依赖 为了使用基于Redis的限流器(`RequestRateLimiter`),需要添加相关的依赖项。确保在项目的 `pom.xml` 文件中包含以下内容: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> ``` 这些依赖支持网关功能和与Redis的集成[^4]。 --- ### 2. 配置 Redis `RequestRateLimiter`默认依赖于Redis来存储限流状态。需要确保已经部署了Redis服务,并且可以在Spring Boot应用中正确访问它。在 `application.yml` 或 `application.properties` 中配置Redis连接信息: ```yaml spring: redis: host: localhost port: 6379 ``` 如果使用的是集群环境或者有密码保护的Redis,还需要进一步配置相关参数。 --- ### 3. 配置 RequestRateLimiter 网关过滤器 接下来,在路由定义中启用`RequestRateLimiter`过滤器。通过在 `application.yml` 文件中配置路由规则来实现: ```yaml spring: cloud: gateway: routes: - id: requestratelimiter_route uri: https://example.org filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20 redis-rate-limiter.registeredOnly: false predicates: - Path=/api/** ``` #### 参数说明: - `replenishRate`: 每秒补充的令牌数。 - `burstCapacity`: 令牌桶的最大容量。 - `registeredOnly`: 是否仅允许注册的用户进行限流,默认为`false`。 --- ### 4. 自定义限流策略(可选) 可以通过自定义 `KeyResolver` 来决定如何根据请求生成限流键值。例如,根据用户的IP地址或请求头中的某个字段进行限流: ```java @Configuration public class RateLimiterConfig { @Bean public KeyResolver userKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); } } ``` 然后在配置文件中引用这个 `KeyResolver`: ```yaml filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20 key-resolver: "#{@userKeyResolver}" ``` --- ### 5. 限流脚本的工作原理 `RequestRateLimiter` 内部会调用一个名为 `request_rate_limiter.lua` 的 Lua 脚本,该脚本负责执行实际的令牌桶算法并更新Redis中的状态。这个脚本通常由 Spring Cloud Gateway 自动加载,无需手动管理[^1]。 --- ### 6. 测试限流效果 启动服务后,可以使用工具如 `curl` 或 Postman 向对应的路径发送请求,观察是否在达到限流阈值后返回 `429 Too Many Requests` 错误。 --- ### 示例代码:完整的 application.yml 配置 ```yaml spring: redis: host: localhost port: 6379 cloud: gateway: routes: - id: requestratelimiter_route uri: https://example.org filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20 key-resolver: "#{@userKeyResolver}" predicates: - Path=/api/** ``` --- ### 注意事项 - 确保Redis服务正常运行,并且网络可达性良好。 - 如果需要更高的性能或分布式场景,可以考虑对Lua脚本进行优化或扩展。 - 在生产环境中,建议对限流策略进行压力测试以验证其行为是否符合预期。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值