Spring Cloud Gateway 的限流配置,核心是确认三件事:限流放在路由级还是全局级、限流键取什么(IP、用户、租户、接口路径)、以及限流触发后返回什么。最小可用写法是用 RequestRateLimiter 过滤器配合 Redis 令牌桶,在路由里引用一个 KeyResolver 和一组参数;但能否直接照抄,取决于你的 KeyResolver 是否已注册、Redis 是否可达、参数是否与业务量级匹配。下面按判断、操作、验证、边界四步展开。
Spring Cloud Gateway 限流建议先用RequestRateLimiter过滤器 + Redis 令牌桶实现路由级限流,KeyResolver 决定限流粒度,redis-rate-limiter.replenishRate/burstCapacity决定速率和突发容量。写配置前先确认三件事:限流键是否唯一可控、Redis 是否与网关同网低延迟、被限流后的响应是否符合客户端预期。改完用固定速率压测观察 429 比例和 Redis 连接状态来验证,没有压测条件时不要凭配置推断效果。
先确认当前场景和目标
限流配置能成立,前提是你的流量已经集中经过网关,而不是各服务各自对外。如果部分接口仍被直连或绕过网关,网关上的限流只能覆盖一部分流量,判断结果会失真,所以第一步是确认入口收敛情况。
接着要明确限的是什么:是保护下游某个慢接口不被打穿,还是控制某个租户的调用总量,还是防止爬虫按 IP 刷接口。这三种目标对应的 KeyResolver 完全不同。按 IP 限流适合无登录态接口,按用户或租户限流适合已鉴权的业务接口,按路径限流只能做粗粒度兜底。
还需要先确认几个环境信息:网关是否已引入 Redis 依赖、Redis 是否与网关同机房、当前接口的合理峰值大概在什么量级、限流触发后客户端能否识别 429。这些信息缺一项,参数就只能拍脑袋填。
按这个顺序处理
第一步,确认依赖和 Redis 连接。使用 Redis 令牌桶限流需要 spring-boot-starter-data-redis-reactive 依赖,以及可用的 Redis 连接配置。没有这一步,过滤器会在运行时报错而不是优雅降级。
spring:
redis:
host: 127.0.0.1
port: 6379
# 按实际环境替换,注意超时不宜过长
timeout: 200ms第二步,定义 KeyResolver。下面是一个按用户 ID 限流的通用骨架,替换项是取用户标识的逻辑,实际项目里通常从请求头或鉴权上下文中取。注意 key 为空时要给出兜底值,否则可能抛异常或所有人共用空 key。

@Configuration
public class RateLimitConfig {
@Bean
public KeyResolver userKeyResolver() {
return exchange -> {
String userId = exchange.getRequest()
.getHeaders().getFirst("X-User-Id");
// 未登录请求统一归到一个兜底 key,避免空值
return Mono.just(userId == null ? "anonymous" : userId);
};
}
}第三步,在路由中挂载过滤器。下面示例是路由级限流,#{@userKeyResolver} 必须与上面 Bean 名称一致;参数值需要结合下游承载能力和业务量级调整,不要直接沿用示例数字。
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- name: RequestRateLimiter
args:
key-resolver: "#{@userKeyResolver}"
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
redis-rate-limiter.requestedTokens: 1如果所有路由都需要统一限流,可以在 default-filters 里配置同样的过滤器,但要意识到这样会让所有路由共用一个 KeyResolver,粒度会变粗。更稳妥的做法是先只挂在高风险路由上,观察稳定后再推广。
第四步,确认限流触发时的响应。默认是 429,如果前端或调用方对状态码有特定处理,可以在过滤器后追加自定义响应,或者统一异常处理里对该状态码做转换。这一步经常被跳过,结果上线后客户端把 429 当成未知错误重试,反而放大流量。
改完后怎么验证
验证的关键是制造可控的固定速率流量,观察三个信号。可以使用 wrk、ab 或脚本循环请求,把并发和速率保持在你设定的 replenishRate 之上,持续一段时间。第一个信号是响应状态码分布:超出令牌桶容量的请求应当返回 429,而不是 500 或超时。第二个信号是 Redis 侧的命令执行是否正常,可以通过 redis-cli monitor 观察限流相关的 Lua 脚本调用是否稳定出现,连接是否频繁断开。第三个信号是下游服务的实际请求量:在限流生效时,下游收到的请求数应明显低于网关收到的请求数,二者差值大致对应被拒绝部分。
验证时还要覆盖 burstCapacity 场景:短时突发请求应允许被放行到 burstCapacity 上限,然后回落。如果突发流量全部被拒,说明 burstCapacity 设置过小;如果持续高频请求几乎不被拒,说明 KeyResolver 取到的 key 分布过于分散或根本没生效,需要回头检查 key 是否为空、是否所有请求落到同一个 key。

最后确认正常业务流量不受影响。用低于限流阈值的速率再跑一轮,预期是全部放行、无 429,且延迟没有明显上升。如果出现偶发 429,通常是 Redis 响应慢导致令牌获取失败,这时候要检查 Redis 负载和网络延迟,而不是继续调大参数。
容易忽略的边界
限流不是万能保护。Redis 令牌桶依赖 Redis 可用性,如果 Redis 与网关之间网络抖动,可能出现误限流或放行异常。建议在 Redis 客户端配置合理的超时,并明确限流失败时的降级策略:是放行还是拒绝。默认行为通常是抛异常,需要结合业务判断是否可接受。
版本差异需要留意。Spring Cloud Gateway 在不同大版本间对 RequestRateLimiter 的参数命名和默认行为有过调整,配置项以你实际使用版本的属性绑定为准,遇到启动报错先核对依赖版本和配置前缀,不要拿其他版本的示例硬套。
还有一种常见误用:把限流当成熔断或隔离手段。限流只控制进入速率,不能解决下游变慢或线程占满的问题,那类问题需要配合超时、熔断和隔离策略。如果目标其实是保护一个已经变慢的下游,单纯限流只能缓解,不能解决根因。
回退建议:先在高风险路由上小范围启用,保留配置开关;一旦发现误限流影响正常业务,立即摘除该路由的过滤器配置,回到无网关限流的状态,再排查 KeyResolver 和 Redis 侧问题。不要在线上直接修改限流参数反复试,验证要在可控流量下完成。