← 返回题目列表

API 网关如何实现限流?

高频 中等 第 5 / 25 题 更新于 2026/07/28
API网关限流令牌桶Redis

简化版

网关限流是在流量入口处控制请求速率,保护后端不被打垮。常用令牌桶算法:一个桶以固定速率放入令牌,每个请求要先拿到令牌才能通过,拿不到就被限流。Spring Cloud Gateway 内置 RequestRateLimiter 过滤器,默认基于 Redis + Lua 脚本实现分布式限流——用 Redis 存令牌桶状态(保证网关多实例间限流数据共享),用 Lua 脚本保证「取令牌」操作的原子性。可以按不同维度限流(按 IP、按用户、按接口),通过 KeyResolver 指定限流的 key。

详细版

为什么在网关限流: 网关是统一入口,在这里限流能把过量请求挡在最前面,保护所有后端服务,且限流规则集中管理。

Spring Cloud Gateway 限流(RequestRateLimiter):

filters:
  - name: RequestRateLimiter
    args:
      redis-rate-limiter.replenishRate: 10    # 令牌桶每秒填充速率(QPS)
      redis-rate-limiter.burstCapacity: 20    # 桶容量(允许的突发)
      key-resolver: "#{@ipKeyResolver}"        # 限流维度(按 IP)
// KeyResolver 决定按什么维度限流
@Bean
KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(
        exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
  • 令牌桶replenishRate 每秒填充令牌数(稳定 QPS),burstCapacity 桶容量(允许突发)。
  • Redis + Lua:Redis 存桶状态(分布式共享),Lua 保证取令牌原子性。
  • KeyResolver:限流维度——按 IP、按用户 ID、按接口路径等。

完整版教学

一、为什么限流放在网关

限流可以在多个层次做(Nginx、网关、应用),但网关是做限流的理想位置

  • 统一入口:所有请求都经过网关,在这里限流能保护所有后端服务,一处配置、全局生效。
  • 挡在最前面:过量请求在网关就被拒绝,根本到不了后端,不占用后端资源,保护最彻底。
  • 规则集中:限流规则在网关统一管理,不用每个后端服务各自实现。

所以网关限流是微服务流量防护的重要一环。

二、令牌桶算法:网关限流的常用算法

Spring Cloud Gateway 的限流基于令牌桶(Token Bucket)算法

  • 有一个,系统以固定速率往桶里放令牌(如每秒放 10 个)。
  • 桶有容量上限(如 20 个),放满了就不再放。
  • 每个请求到来,要先从桶里取一个令牌——取到了才放行通过,取不到(桶空了)就被限流(拒绝或排队)。

令牌桶的特点:

  • replenishRate(填充速率) 控制平均 QPS——长期看,请求通过的速率不超过填充速率。
  • burstCapacity(桶容量) 允许突发流量——因为桶里可以攒着令牌,短时间来一批请求能一次性取走桶里攒的令牌通过(应对突发),只要不超过桶容量。

对比漏桶(Nginx 用的):令牌桶允许突发(桶里攒的令牌可一次用掉),漏桶是严格匀速。令牌桶更灵活,能兼顾「限平均速率」和「容忍突发」。

三、为什么要用 Redis + Lua(分布式限流)

网关通常部署多个实例(高可用 + 负载均衡)。如果每个网关实例各自在本地内存做限流,就有问题:假设限流 100 QPS、部署了 5 个网关实例,每个实例本地限 100,总共就放行了 500 QPS——限流失效

所以网关限流必须是分布式限流——多个网关实例共享同一份限流状态。Spring Cloud Gateway 用 Redis 存令牌桶的状态(令牌数量、上次填充时间),所有网关实例都读写同一个 Redis 里的桶,这样无论多少个网关实例,总的限流是准确的

为什么还要 Lua 脚本:「取令牌」这个操作涉及多步(读当前令牌数、计算该补多少、判断够不够、扣减)——如果不是原子的,高并发下多个请求同时操作会竞态(都读到还有令牌、都通过,超过限制)。Lua 脚本在 Redis 里是原子执行的(Redis 单线程执行整个脚本,中间不被打断),把「取令牌」的多步逻辑放进一个 Lua 脚本,保证了原子性和限流的准确。

四、限流维度:KeyResolver

限流要按某个维度进行——是按 IP 限、按用户限、还是按接口限?Spring Cloud Gateway 用 KeyResolver 决定限流的 key

  • 按 IP 限流KeyResolver 返回客户端 IP——每个 IP 独立限流(防单个 IP 刷接口)。
  • 按用户限流:返回用户 ID(从 Token 解析)——每个用户独立限流。
  • 按接口限流:返回请求路径——每个接口独立限流。
  • 全局限流:返回固定值——整个网关一个桶。

不同 key 对应不同的令牌桶。选对维度很重要:按 IP 防单机攻击,按用户防单用户滥用,按接口保护特定慢接口。

五、限流的其他考量

  • 限流后的响应:被限流的请求,网关默认返回 429 Too Many Requests。可以自定义响应(友好提示、降级数据)。
  • 限流 + 熔断降级配合:限流控入口流量,熔断切故障依赖,降级给兜底——共同构成流量防护(见「网关熔断降级」专题)。
  • Redis 的可用性:限流依赖 Redis,Redis 挂了限流会受影响,要考虑 Redis 高可用或降级策略(如 Redis 不可用时放行或本地兜底限流)。
  • 也可用 Sentinel:Spring Cloud Alibaba 的 Sentinel 提供更强大的限流(多种规则、热点限流、集群限流),可替代默认的 RequestRateLimiter。

六、常见误区与追问

这道题面试时最容易丢分的地方,是把「网关限流」答成一段泛泛的组件介绍。更稳的答法是先给结论,再沿着 统一流量入口链路 拆清楚流程,最后补上异常场景、数字边界和选型取舍。

回答层次要讲清的内容容易漏掉的边界
核心定义网关限流在流量入口按 IP、用户、接口、租户等维度控制请求速率,常用令牌桶、漏桶和滑动窗口不要停在名词解释
流程机制请求进入网关 -> 提取限流 key -> 执行限流算法 -> 未超限则转发 -> 超限返回 429 或降级响应说明谁触发、谁存储、谁通知、谁兜底
工程取舍令牌桶容量 100、生成速率 50 QPS 时,最多允许短时突发 100 个请求,长期速率约 50 QPS网关适合收口横切能力,但不能把业务逻辑堆到网关,否则会形成新的复杂单体
网关限流 面试拆解:
1. 请求进入网关
2. 提取限流 key
3. 执行限流算法
4. 未超限则转发
5. 超限返回 429 或降级响应

记忆钩子:先拆路由、过滤器、鉴权、限流、熔断、灰度,再说明网关和业务服务的边界;回答时一定要落到题目中的「网关限流」,不要把相邻中间件的能力混着讲。

  • 误区:限流只按接口做就够了。 还要按用户、IP、租户、AppKey 等维度防止单个调用方打爆系统。
  • 误区:本地限流适合所有网关集群。 多节点网关要全局限流时需要 Redis、限流服务或一致哈希分摊。
  • 误区:限流阈值越低越安全。 过低会误伤正常流量,应结合容量压测和业务优先级设置。
  • 追问:令牌桶和漏桶区别是什么? 令牌桶允许一定突发,漏桶更强调平滑固定速率输出。
  • 追问:网关限流返回什么状态码? HTTP 常用 429 Too Many Requests,也可返回业务约定降级结果。
  • 追问:热点接口如何保护? 单独设置更细粒度阈值,配合缓存、降级和隔离。

七、加强记忆

网关限流在流量入口保护后端(挡在最前、保护所有服务、规则集中)。Spring Cloud Gateway 用 RequestRateLimiter + 令牌桶算法:桶以 replenishRate(平均 QPS) 匀速放令牌、burstCapacity(桶容量,允许突发),请求取到令牌才通过(令牌桶允许突发,区别于漏桶严格匀速)。默认基于 Redis + LuaRedis 存桶状态(多网关实例共享,实现分布式限流,否则各实例本地限流会导致总量超标)、Lua 脚本保证取令牌原子性(防高并发竞态)。KeyResolver 决定限流维度(按 IP / 用户 / 接口 / 全局)。被限流返回 429。也可用 Sentinel 做更强限流。口诀:令牌桶控速率允突发、Redis+Lua 做分布式原子限流、KeyResolver 选维度