You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Spring Cloud Gateway与Redis实现请求限流的疑问及场景配置咨询

Spring Cloud Gateway 结合 RedisRateLimiter 实现限流详解

一、RedisRateLimiter 是什么?

RedisRateLimiter 是 Spring Cloud Gateway 提供的基于令牌桶算法的分布式限流组件,依赖 Redis 存储限流状态,通过 Lua 脚本保证限流逻辑的原子性,避免分布式环境下的并发问题,适合多实例网关的统一限流场景。

二、核心工作原理

它实现了令牌桶算法的核心逻辑:

  1. 令牌生成:以固定速率(replenishRate)向令牌桶中添加令牌,比如每分钟生成5个令牌,相当于每秒生成约0.083个。
  2. 令牌消耗:每个请求过来时,尝试从桶中获取指定数量的令牌(默认1个):
    • 成功获取到令牌:请求放行,桶中令牌数减少对应数量。
    • 无法获取令牌:请求被限流,返回429 Too Many Requests。
  3. 令牌桶容量:桶的最大容量由burstCapacity定义,当桶满时,新生成的令牌会被丢弃,避免令牌无限累积。

三、核心参数解析

RedisRateLimiter 的核心参数对应令牌桶的关键配置:

  • replenishRate:每分钟生成的令牌数,决定了长期允许的平均请求速率。
  • burstCapacity:令牌桶的最大容量,决定了允许的突发请求峰值(比如短时间内允许超过平均速率的请求数)。
  • requestedTokens:每个请求消耗的令牌数,默认值为1,可根据业务调整(比如一个复杂请求消耗2个令牌)。

四、对应限流规则的配置示例

针对你需要的3种限流规则,结合场景解释配置逻辑:

1. 规则1:每分钟最多5次请求

配置参数:replenishRate=5,burstCapacity=5

  • 逻辑说明:
    • 令牌桶每分钟生成5个令牌,初始时桶内装满5个令牌。
    • 如果连续发送5个请求,桶内令牌耗尽,后续每个请求需要等待约12秒(60/5)才能获取到新生成的令牌,确保每分钟总请求数不超过5。
    • 不允许突发请求(因为桶容量等于生成速率),严格控制在每分钟5次以内。

2. 规则2:每分钟最多7次请求

配置参数:replenishRate=7,burstCapacity=7

  • 逻辑说明:
    • 令牌桶每分钟生成7个令牌,初始桶内有7个令牌。
    • 连续发送7个请求后,桶空,后续请求需等待约8.57秒(60/7)才能拿到令牌,保证每分钟总请求数不超过7。
    • 同样严格限制速率,无突发空间。

3. 规则3:每分钟最多20次请求

配置参数:replenishRate=20,burstCapacity=20

  • 逻辑说明:
    • 令牌桶每分钟生成20个令牌,初始桶内有20个令牌。
    • 连续发送20个请求后,桶空,后续请求需等待3秒(60/20)即可获取令牌,确保每分钟总请求数不超过20。

如果需要允许一定的突发请求(比如某一秒内允许发送20个请求,之后每分钟只能保持20次的平均速率),可以将burstCapacity设为更大的值,比如burstCapacity=40,但replenishRate仍为20,这样短时间内可以处理40个请求,但后续每分钟只能处理20个,直到令牌桶重新填满。

五、你的现有代码优化建议

1. 修正 RedisRateLimiter 构造参数

你当前的代码中第三个参数传了60,这是错误的。在Spring Boot 2.5.12对应的版本中,RedisRateLimiter的第三个参数是defaultRequestedTokens(每个请求消耗的令牌数),默认值为1,不需要手动设置为60。正确的全局默认配置应该是:

@Bean
public RedisRateLimiter redisRateLimiter() {
    // 这里可以设一个全局默认值,比如每分钟10次
    return new RedisRateLimiter(10, 10);
}

2. 实现不同路由的差异化限流

如果需要给不同接口配置不同的限流规则,无需定义多个RedisRateLimiter Bean,只需在路由配置中通过metadata指定参数即可:

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
            // 接口1:每分钟5次
            .route("api1", r -> r.path("/api/v1/**")
                    .filters(f -> f.requestRateLimiter(c -> c
                            .rateLimiter(redisRateLimiter())
                            .keyResolver(ipKeyResolver())
                            // 通过metadata指定限流参数
                            .configureRateLimiter(rl -> rl.setReplenishRate(5).setBurstCapacity(5))))
                    .uri("http://localhost:8081"))
            // 接口2:每分钟7次
            .route("api2", r -> r.path("/api/v2/**")
                    .filters(f -> f.requestRateLimiter(c -> c
                            .rateLimiter(redisRateLimiter())
                            .keyResolver(ipKeyResolver())
                            .configureRateLimiter(rl -> rl.setReplenishRate(7).setBurstCapacity(7))))
                    .uri("http://localhost:8082"))
            // 接口3:每分钟20次
            .route("api3", r -> r.path("/api/v3/**")
                    .filters(f -> f.requestRateLimiter(c -> c
                            .rateLimiter(redisRateLimiter())
                            .keyResolver(ipKeyResolver())
                            .configureRateLimiter(rl -> rl.setReplenishRate(20).setBurstCapacity(20))))
                    .uri("http://localhost:8083"))
            .build();
}

3. KeyResolver 代码优化

你的IP限流KeyResolver可以简化,无需嵌套Optional操作:

@Component
public class IpKeyResolver implements KeyResolver {
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.justOrEmpty(exchange.getRequest().getRemoteAddress())
                .map(InetSocketAddress::getHostString);
    }
}

内容的提问来源于stack exchange,提问作者Alpesh Jikadra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 09:03:13