Skip to content

分布式限流:算法、共享状态与故障策略 ​

修订于 2026-10-12:原文的促销事故、QPS 能力和无来源的配置阈值已删除。限流参数必须依据业务目标和负载测试确定。

限流要先回答“限制什么”:每个用户、每个 API Key、每个租户、每条路由,还是整个服务?同一个数值放在不同维度上,保护效果和误伤范围完全不同。

常见算法 ​

方法主要特性需要注意
固定窗口计数实现简单,按时间窗口统计请求数。相邻窗口边界可能出现短时突增。
滑动窗口更接近最近一段时间的真实请求量。状态与计算成本通常更高。
令牌桶允许在持续速率之外容纳一定突发量。要分别设置补充速率与桶容量。
漏桶更关注以稳定速率处理或放行。排队空间和等待时间需受控。

算法名称不能直接决定产品行为。AWS API Gateway 文档说明其令牌桶节流是 best effort 的目标,而非严格不可突破的请求上限。Nginx 的 limit_req 文档则说明该模块使用漏桶方法。以具体产品文档为准。

多实例为什么更难 ​

如果每个实例只维护本地计数,同一用户的请求被负载均衡到不同实例时,就可能绕过期望的全局限制。共享存储可以统一状态,但每次请求都访问共享点,会引入延迟和新的故障依赖。

Redis 文档展示了固定窗口计数、滑动窗口和令牌桶等方案。对于“读取状态 → 判断 → 更新状态”的过程,要考虑并发原子性;简单地分开执行计数与过期设置可能产生竞态,具体实现应遵循产品文档。还应设置键生命周期和内存边界。

故障时如何处理 ​

限流器自身不可用时,系统可以选择放行、拒绝或退回到本地保护,但每种选择都有代价:

  • 放行可能让下游过载。
  • 拒绝可能扩大故障影响。
  • 本地限制能提供部分保护,但无法保证全局配额。

应按接口重要性定义故障策略,并对外返回清晰状态。客户端收到 429 后可按服务端提示和剩余期限决定是否退避重试;不能立即无限重试。

上线验证 ​

  1. 用真实流量估算持续速率、峰值和关键租户分布。
  2. 在多实例环境测试窗口边界、并发请求和共享存储失效。
  3. 记录允许、拒绝、排队和限流器错误数量;分别看误伤与下游保护效果。
  4. 测试热键、恶意请求和突发流量,避免限流状态成为新的瓶颈。
  5. 给参数留回滚与调节路径;不用单个通用 QPS 值覆盖所有接口。

参考资料 ​

梧桐和风 · 让复杂的技术讲得更清楚