限流模式Skill rate-limiting-patterns

限流模式技能用于设计和实现API限流、节流和配额管理方案,以保护服务和系统免受滥用、DDoS攻击和资源耗尽。关键算法包括令牌桶、滑动窗口等,适用于分布式环境、云服务和网络安全。关键词:API限流、令牌桶算法、分布式限流、配额管理、系统保护、节流模式。

架构设计 0 次安装 0 次浏览 更新于 3/11/2026

name: rate-limiting-patterns description: 用于实现限流、节流或API配额的模式。涵盖令牌桶、滑动窗口等算法,以及分布式限流模式。 allowed-tools: Read, Glob, Grep

限流模式

通过限流、节流和配额管理来保护API和服务的模式。

何时使用此技能

  • 实现API限流
  • 选择限流算法
  • 设计分布式限流
  • 设置配额管理
  • 防止滥用

为什么需要限流

保护免受:
- DDoS攻击
- 暴力尝试
- 资源耗尽
- 成本超支(云API)
- 级联故障

业务好处:
- 公平资源分配
- 可预测的性能
- 成本控制
- SLA强制执行

限流算法

令牌桶

概念: 以固定速率添加令牌,请求消耗令牌

配置:
- 桶大小(最大令牌数):100
- 填充速率:10个令牌/秒

行为:
┌─────────────────────────┐
│ 桶(容量:100)          │
│ ████████████░░░░░░░░░░   │ 60个可用令牌
└─────────────────────────┘
        ↑           ↓
   10个令牌/秒   请求消耗1个令牌

允许突发流量达到桶大小,然后限流。

特性:

  • 允许受控突发
  • 简单实现
  • 内存高效
  • 最常用算法

实现草图:

token_bucket:
  tokens = min(tokens + (now - last_update) * rate, capacity)
  if tokens >= cost:
    tokens -= cost
    return ALLOW
  return DENY

漏桶

概念: 请求排队并以固定速率处理

┌─────────────────────────┐
│ 队列(容量:100)        │
│ ██████████████████████   │ 等待的请求
└──────────┬──────────────┘
           │
           ▼ 以固定速率处理(10/秒)
       [处理中]

平滑流量至恒定速率。

特性:

  • 平滑输出速率
  • 不允许突发
  • 请求可能排队
  • 适合下游保护

固定窗口

概念: 在固定时间窗口内计数请求

窗口:1分钟,限制:100个请求

|-------- 窗口 1 --------|-------- 窗口 2 --------|
   95个请求                   ?个请求
   [允许]                      [重置为0]

问题:边界突发
窗口1结束:100个请求
窗口2开始:100个请求
= 在约1秒内200个请求

特性:

  • 简单实现
  • 内存高效
  • 边界突发问题
  • 适合简单用例

滑动窗口日志

概念: 跟踪每个请求的时间戳

窗口:1分钟,限制:100

请求:[t-55秒, t-50秒, t-45秒, ..., t-5秒, t-2秒, 现在]
计数[现在 - 60秒, 现在]内的所有请求

无边界突发问题,但内存密集。

特性:

  • 精确限流
  • 无边界问题
  • 内存密集(存储所有时间戳)
  • 适合严格限制

滑动窗口计数器

概念: 当前和先前窗口的加权平均值

先前窗口:80个请求
当前窗口:30个请求(窗口进行40%)

加权计数 = 80 * 0.6 + 30 = 78
限制:100
结果:允许(78 < 100)

特性:

  • 近似(通常足够好)
  • 内存高效
  • 平滑边界问题
  • 最适合大多数情况

算法选择指南

算法 突发处理 内存 精度 用例
令牌桶 允许突发 通用API限流
漏桶 不允许突发 平滑速率强制执行
固定窗口 边界突发 极低 简单限制
滑动日志 不允许突发 精确 严格合规
滑动计数器 最小突发 最佳通用选择

分布式限流

挑战

单节点:简单的内存计数器
多节点:需要协调

无协调:
节点1:50个请求(低于100限制)
节点2:50个请求(低于100限制)
节点3:50个请求(低于100限制)
总计:150个请求(超过100限制!)

模式1:集中式(Redis)

┌─────────┐     ┌─────────┐     ┌─────────┐
│ 节点1   │     │ 节点2   │     │ 节点3   │
└────┬────┘     └────┬────┘     └────┬────┘
     │               │               │
     └───────────────┼───────────────┘
                     │
              ┌──────▼──────┐
              │    Redis    │
              │ (计数器)   │
              └─────────────┘

优点:准确、一致
缺点:Redis依赖、延迟、单点故障

模式2:本地 + 同步

每个节点获取限制的一部分:
- 3个节点,100限制 → 每个节点33

定期同步以重新平衡未使用的容量。

优点:低延迟、弹性
缺点:精度较低、同步复杂

模式3:粘性会话

将同一客户端路由到同一节点(通过IP、API密钥等)

优点:简单、无需协调
缺点:负载不均、故障转移复杂

Redis实现

令牌桶与Redis:

EVALSHA token_bucket_script 1 {key}
  {capacity} {refill_rate} {tokens_requested}

脚本:
1. 获取当前令牌和时间戳
2. 计算自上次请求以来添加的令牌
3. 如果足够令牌,扣除并允许
4. 返回剩余令牌

限流头部

标准头部,用于向客户端通信限制:

HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1640000000
Retry-After: 30  (当限流时)

或草案标准:
RateLimit-Limit: 100
RateLimit-Remaining: 45
RateLimit-Reset: 30

限流响应

HTTP/1.1 429 过多请求
Content-Type: application/json
Retry-After: 30

{
  "error": {
    "code": "RATE_LIMITED",
    "message": "超出限流",
    "retry_after": 30,
    "limit": 100,
    "window": "1m"
  }
}

多层级限流

在多个层级应用限制:

层级1:全局(保护基础设施)
  - 所有客户端10,000请求/秒

层级2:每租户(公平分配)
  - 每个组织1,000请求/分钟

层级3:每用户(防止滥用)
  - 每个用户100请求/分钟

层级4:每端点(保护昂贵操作)
  - /export端点10请求/分钟

配额管理

配额 vs 限流

限流:每时间窗口的请求数(突发保护)
  - 100请求/分钟

配额:周期内的总分配(预算)
  - 10,000 API调用/月

配额跟踪

跟踪使用情况:
- 每个API密钥
- 每个端点
- 每个操作类型

警报阈值:
- 80%使用率:警告通知
- 100%使用率:硬阻止或超支收费

最佳实践

优雅降级

替代硬阻止:
1. 降低质量(更低分辨率、更少结果)
2. 队列请求(稍后处理)
3. 提供缓存响应
4. 允许突发但带惩罚(恢复更慢)

客户端处理

实现指数退避:
1. 收到429
2. 等待Retry-After(或1秒)
3. 重试
4. 如果再次429,等待2秒
5. 继续加倍直到最大(例如,60秒)

测试限流

测试场景:
- 突发流量
- 持续高流量
- 时钟偏差(分布式系统)
- 限制后恢复
- 多种客户端类型

相关技能

  • api-design-fundamentals - API设计模式
  • idempotency-patterns - 安全重试
  • quality-attributes-taxonomy - 性能属性