Gateway 限流:RequestRateLimiter 与 Redis 实现

网关是所有流量的必经之路,天然适合做限流:把超出的请求挡在服务入口之外,保护后端不被突增流量冲垮。Spring Cloud Gateway 内置的 RequestRateLimiter 过滤器基于令牌桶算法,配合 Redis 实现分布式计数,是官方主推的方案。

为什么计数器放在 Redis

网关通常会多实例部署,若每个实例各自计数,限流总量会变成"实例数 × 单机限额",形同虚设。把令牌桶的状态放到 Redis,所有实例读写同一份计数,才能做到全局准确。Redis 的 Lua 脚本保证了"取令牌"操作的原子性,这是该方案可靠的前提。

令牌桶语义速记

令牌桶有两个参数:replenishRate 表示每秒向桶里补充的令牌数,决定长期平均速率;burstCapacity 表示桶容量,决定瞬间允许的突发量。每次请求消耗 requestedTokens(默认 1)个令牌,桶空了请求就被拒绝。直观理解:replenishRate=10、burstCapacity=20 表示平均每秒 10 个请求,但允许瞬间最多 20 个并发突发。

准备依赖与 Redis

网关工程引入反应式 Redis 依赖,并保证 Redis 可用:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
spring:
  data:
    redis:
      host: localhost
      port: 6379
      # 若 Redis 同时被其他 Spring Data 功能使用,官方建议关闭 repositories 自动装配
      # repositories:
      #   enabled: false

声明限流过滤器

在目标路由上挂 RequestRateLimiter,key-resolver 指向一个限流维度 Bean(见下):

spring:
  cloud:
    gateway:
      routes:
        - id: order-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10     # 每秒补充令牌
                redis-rate-limiter.burstCapacity: 20     # 桶容量
                redis-rate-limiter.requestedTokens: 1    # 每请求消耗
                key-resolver: "#{@ipKeyResolver}"        # 限流维度

定义限流维度:KeyResolver

按什么粒度限流取决于业务:按客户端 IP、按登录用户、按接口都行。KeyResolver 把请求映射成一个限流 key:

@Bean
KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(
            exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}

按 IP 限流能防单点刷量,但多级代理后 IP 可能不可靠(需正确取 X-Forwarded-For);按用户限流更贴近业务(如每个用户每秒最多 N 次),登录场景优先;也可以按"IP + 用户"组合。key 的维度决定规则颗粒度,也决定 Redis 里 key 的数量,注意不要设计出无界增长的 key。

行为与排障

超过限额的请求会被网关直接拒绝并返回 429(Too Many Requests),业务方应捕获该状态做"稍后重试"提示。常见问题:一是忘记引入 reactive Redis 依赖,启动报找不到 RedisRateLimiter 相关 Bean;二是 key-resolver 名字写错,限流不生效或抛异常;三是只配了 replenishRate 没配 burstCapacity(burst 不配置时默认等于 replenish 值,官方文档有说明);四是限流 key 为 null 时会被当作非法请求处理。

与 Sentinel 网关限流的取舍

RequestRateLimiter 适合"网关统一按 Redis 做速率限制"的朴素场景。若需要更丰富的规则(按调用方、动态规则下发、与熔断联动),可在网关上集成 Sentinel 的网关适配模块,二者选型对比以官方文档为准。本教程后续 Sentinel 章节面向服务侧限流,概念可以互通。

小结

限流三件套:令牌桶参数定速率、KeyResolver 定维度、Redis 保全局一致。把"每秒多少请求、突发多少、按谁计数"三个问题回答清楚,配置就完成了。下一部分离开流量入口,转向配置中心,让"改配置不重启"成为可能。

笔记加载中…