跳转到内容
Glossary 2 分钟阅读 1337 次浏览

速率限制

了解速率限制与请求限流,保护您的 API 免受滥用。掌握管理流量、防止过载的有效策略。

速率限制

速率限制(rate limiting),也称为请求限流(request throttling),是一种控制用户或服务向 API 或服务器发送请求速率的机制,用于防止滥用、保证资源的公平分配并维持系统稳定。

理解速率限制

速率限制保护服务免受过量请求的冲击,避免性能下降、拒绝服务(DoS)攻击或资源耗尽。它确保系统资源对所有合法用户可用,并防止单一主体独占访问。代理服务在实施这些限制时通常扮演关键角色:既可以在客户端请求到达上游服务之前对其施加限制,也可以将上游的限制信息回传给客户端。

为什么要实施速率限制?

  • 资源保护: 防止服务器被过多请求压垮,节省 CPU、内存和网络带宽。
  • 防止滥用: 通过限制请求尝试次数,缓解暴力破解、撞库(credential stuffing)等恶意行为。
  • 公平使用: 确保所有客户端公平地访问共享资源,防止单个客户端独占系统。
  • 成本控制: 对于按用量计费的服务,速率限制可通过设定资源消耗上限来控制运营成本。

常见的速率限制算法

实现和执行速率限制有多种算法,它们在处理突发流量和资源占用方面各有特点。

令牌桶(Token Bucket)

Token Bucket 算法把限流建模为一个容量固定的桶,桶以恒定速率补充令牌。每个请求消耗一个令牌。桶为空时,请求被拒绝或排队。该算法允许一定程度的突发:只要桶内有令牌,请求可以在桶容量范围内一次消耗多个令牌。

漏桶(Leaky Bucket)

Leaky Bucket 算法以固定的输出速率处理请求。请求被加入队列(即"桶")。队列满时,新请求被拒绝。请求以恒定速率从桶中"漏出",保证处理流量平稳。该算法能削平突发,但会给必须在队列中等待的请求带来延迟。

固定窗口计数器(Fixed Window Counter)

在 Fixed Window Counter 算法中,先定义一个时间窗口(例如 60 秒),由计数器统计该窗口内的请求数。窗口到期后计数器归零。窗口内超出限额的请求被拒绝。其缺点是窗口边界处的"突发问题":客户端可能在两个相邻窗口内发送两倍于限额的请求。

滑动窗口日志(Sliding Window Log)

Sliding Window Log 算法为每个请求记录一个时间戳。新请求到达时,系统统计最近 N 秒(即窗口)内的时间戳数量。若该数量超过限额,请求被拒绝。该方法精确,但因为要保存所有时间戳,内存开销较大。

滑动窗口计数器(Sliding Window Counter)

该算法结合了 Fixed Window 与 Sliding Window Log 的特点,在不承担逐条记录请求的内存开销的前提下缓解边界问题。它使用两个固定窗口:当前窗口和上一个窗口。当前请求的时间戳决定其在当前窗口中的位置。允许的请求数按当前窗口已过去的比例,取上一窗口计数与当前窗口计数的加权平均值。

算法对比

特性 Token Bucket Leaky Bucket Fixed Window Counter Sliding Window Log Sliding Window Counter
突发处理 允许突发 削平突发 易受突发影响 处理良好 处理良好
资源占用 中等 中等 高(内存) 低到中等
复杂度 中等 中等 中等
精确度 良好 良好 差(边界情况) 良好
延迟影响 低(有令牌时) 高(排队)

识别速率限制

超出速率限制时,API 或服务通常会返回特定的 HTTP 状态码和响应头。

HTTP 状态码 429 Too Many Requests

速率限制的标准 HTTP 状态码是 429 Too Many Requests,表示用户在给定时间内发送了过多请求。

HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json

{
  "error": "Rate limit exceeded. Try again in 30 seconds."
}

响应头

API 通常会附带特定的响应头,提供更多关于限流状态及应对方式的信息。

  • Retry-After(RFC 7231 第 7.1.3 节)指示 user agent 在发起后续请求前应等待多久。取值可以是表示秒数的整数,也可以是具体的日期/时间。
  • X-RateLimit-Limit 当前限流窗口内允许的最大请求数。
  • X-RateLimit-Remaining 当前限流窗口内剩余的请求数。
  • X-RateLimit-Reset 当前限流窗口重置的时间(通常为 Unix epoch 秒)。

这些 X-RateLimit-* 响应头很常见,但并未被任何 RFC 标准化;不同服务的具体命名和行为可能不同。

应对速率限制

在客户端妥善处理速率限制,是构建与外部服务交互的健壮应用的关键。

带抖动的指数退避

这是重试失败请求(包括因限流而失败的请求)的标准策略。

  1. 指数退避: 客户端在两次重试之间等待呈指数增长的时间(例如 1 秒、2 秒、4 秒、8 秒)。
  2. 抖动(jitter): 在退避时长上叠加一个小的随机延迟。这样可以避免限流重置后所有客户端同时重试,从而引发新一轮限流。
import time
import random
import requests

def make_request_with_retry(url, max_retries=5):
    retries = 0
    while retries < max_retries:
        try:
            response = requests.get(url)
            if response.status_code == 429:
                retry_after = int(response.headers.get('Retry-After', 1))
                print(f"Rate limited. Retrying after {retry_after} seconds.")
                time.sleep(retry_after)
            elif 200 <= response.status_code < 300:
                return response
            else:
                response.raise_for_status() # 其他 HTTP 错误抛出异常
        except requests.exceptions.RequestException as e:
            print(f"Request failed: {e}")

        # 带抖动的指数退避
        delay = (2 ** retries) + random.uniform(0, 1) # 2^retries + 0 到 1 之间的随机小数
        print(f"Retrying in {delay:.2f} seconds...")
        time.sleep(delay)
        retries += 1

    raise Exception(f"Failed to make request after {max_retries} retries.")

# 用法示例:
# response = make_request_with_retry("https://api.example.com/data")
# if response:
#     print("Request successful:", response.json())

遵守 Retry-After 响应头

如果 API 返回了 Retry-After 响应头,客户端必须遵守该指令。其值规定了向同一 endpoint 再次发送请求前的最短等待时间。

客户端缓存

对访问频繁且不常变化的 endpoint 的响应做缓存。这能减少发往 API 的请求数量,间接帮助您保持在限额之内。

合并请求

如果 API 支持,请把多个小操作合并成一次较大的请求,从而减少 API 调用总数。

预测性限流

客户端可以监控自身的请求速率,在接近已知限额时主动降速或暂停,而不是等到收到 429 响应。这需要事先了解该 API 的速率限制。

面向速率限制的代理服务配置

健全的代理服务提供完善的限流管理能力,既覆盖通过代理访问服务的客户端,也覆盖代理自身与上游 API 的交互。

对入站流量施加限制

代理可以按多种维度对客户端的入站请求施加速率限制。

  • 客户端 IP 地址: 限制来自单个 IP 的请求。
  • API 密钥/令牌: 限制与特定认证凭据关联的请求。
  • 用户 ID: 当代理能从响应头或令牌中提取用户信息时使用。
  • 路径/endpoint: 为不同的 API endpoint 设置不同限额(例如 /search 的限额可以高于 /admin/delete)。
# 示例:按 IP 限流的代理配置
http:
  routers:
    api-router:
      rule: "Host(`api.example.com`)"
      service: api-service
      middlewares: [rate-limit-ip]
  middlewares:
    rate-limit-ip:
      rateLimit:
        average: 100 # 每秒请求数
        burst: 50    # 超出平均值的最大突发量
        sourceCriterion: "ipStrategy" # 按来源 IP 分别限流

管理发往上游服务的出站流量

当代理自身调用上游 API 时,它可以实施自己的速率限制,以免压垮这些外部服务。在代理需要汇聚多个数据源的集成场景中,这一点尤为关键。

  • 针对上游的独立限额: 为代理对接的每个上游服务分别配置速率限制。
  • 熔断(circuit breaking): 将速率限制与熔断器模式结合,在上游服务无响应或持续对代理限流时隔离故障。

定制化与粒度

高级代理配置支持对速率限制进行精细控制:

  • 动态限额: 根据后端健康状况、时段或其他运营指标调整限额。
  • 分级限额: 为不同等级的客户端设置不同限额(例如免费用户与付费用户)。
  • 配额管理: 在短期限流之外,按更长周期的配额(例如每月请求数)统计用量。

监控与告警

代理服务应提供监控速率限制统计数据的工具:

  • 请求计数: 统计请求总数、成功请求数以及被限流的请求数。
  • 限额突破: 当特定客户端或上游服务接近或超出限额时发出告警。
  • 用量趋势: 可视化一段时间内的请求模式,识别潜在瓶颈或滥用行为。

监控有助于运维团队理解流量模式、优化速率限制配置,并在问题影响服务可用性之前主动处理。

已更新: 03.03.2026
返回分类

试用我们的代理

遍布 100+ 国家的 20,000+ 代理

support_agent
GProxy Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.