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

速率限制

了解速率限制与请求限流,保护您的 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.