按用户配的限流是 10 QPS,上线后第 11 个请求换另一个用户也被拒,日志里 KeyResolver 打出来的 key 全是同一个,明显不对。日志里能对上时间点,这种反而好排。
KeyResolver 默认拿 remoteAddress 做 key,前面还有一层负载均衡,所有请求看到的都是同一台代理的地址,等于全站共用一个令牌桶,按用户限流直接失效。这一点先确认清楚,后面就不用反复试。
@Bean
public KeyResolver userKeyResolver() {
return ex -> Mono.justOrEmpty(
ex.getRequest().getHeaders().getFirst('X-User-Id'));
}
「网关限流 KeyResolver」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。
别只看报错的最后一行,往上看几行,真正的起因通常在上面。
处理上按这个顺序:key 改成从认证信息里取用户 id,取不到的时候再退回 IP;取客户端 IP 时读 X-Forwarded-For 里的第一段地址,不要用 socket 连接地址;key 为空要有一个兜底逻辑,别让异常把整个请求打成 500。
结果对不对很好判断,两个用户并发压测各自独立计数,A 被限流时 B 仍然正常通过,互不影响。
