跳转到内容

限流与背压

用途:流量突增、下游变慢时保护自己的系统

层次 目标 手段
入口限流 保护自身容量 计数器/滑动窗口/令牌桶/漏桶 + 快速拒绝
并发度控制 限制在途请求数 信号量、连接池上限、线程池队列
背压传递 让上游感知并降速 有界队列 + 拒绝、429/Retry-After、响应式背压

并发度控制常被忽略却最有效:按利特尔法则,允许在途数 = 目标 QPS × 下游 P99 耗时。下游变慢时在途数会自然膨胀,限住并发就限住了内存与排队。

算法 特点 适用
固定窗口计数 实现最简单,临界点可放行 2 倍流量 粗粒度保护
滑动窗口 平滑临界问题,内存与实现稍复杂 QPS 限流
令牌桶 允许突发(桶内余量),平均速率受控 大多数业务入口
漏桶 恒定速率流出,不允许突发 保护下游(如批量写入)
自适应并发 按 RT 与队列动态调整(梯度/小队列原则) 下游耗时波动大的场景

限流只有配合降级才有意义:

  1. 快速失败:返回明确错误码与 Retry-After,不要静默丢弃。
  2. 排队兜底:短时有界队列(毫秒级),超过即拒。
  3. 降级路径:返回缓存值、简化结果、关闭非核心功能。
  4. 优先级:核心链路(支付、下单)优先,非核心(推荐、导出)先拒。
  5. 配额隔离:按调用方/租户限,防止单个来源拖垮全局。

单机限流在集群下需要换算总量。集中式方案(Redis + 原子操作、专用限流服务)准确但有额外 RT 与可用性依赖;本地方案(每台分摊额度 + 定期再平衡)性能好但精度弱。选择依据:是否允许超发与能否接受中心组件故障。

开源参考:Alibaba Sentinel(流控、熔断、热点参数限流)、Resilience4j、Guava RateLimiter(单机令牌桶)、Envoy/Nginx 层限流、API 网关内置配额。

  • 超时:必须有,否则线程被占满,限流形同虚设。
  • 熔断:下游故障时快速失败,给其恢复空间;半开探测恢复。
  • 重试预算:重试流量要计入配额(例如重试不超过总请求的 10%),否则限流被自家重试打穿。
  • 退避 + 抖动:避免同步重试造成二次洪峰。
误区 修正
只限 QPS 不限并发 下游变慢时 QPS 很低但线程已满
队列越大越“稳” 只是把故障变成用户超时,且增加 OOM 风险
限流阈值凭感觉设 用压测确定单实例容量,再留 20-30% 余量
拒绝无监控无告警 拒绝次数必须看板化并设阈值
所有调用方共用一个配额 按来源/租户隔离
  • Martin Kleppmann《数据密集型应用系统设计》第 6 章(背压与批量)
  • Ben Maurer《Rate Limiting, Stores, and Slack》(Meta 的生产实践论述)
  • Sentinel / Resilience4j 官方文档