跳到主要内容
版本:1.4.0

API Key 与模型限流

限流可以保护模型服务提供方容量,并防止单个调用方或模型耗尽共享配额。当配额属于某个调用方时,请在调用方 API Key 上配置限制;当使用某个模型的所有调用方应共享配额时,请在模型上配置限制。

这些限制属于其所配置的 API Key 或模型。限流策略是独立规则,可以匹配团队、成员、API Key、模型、模型名称或模型服务提供方,并把匹配流量划分到彼此独立的配额桶中。同一请求可以同时匹配 API Key 限制、模型限制和策略。每个匹配的限制都会生效;只要有任一配额桶耗尽,网关就会在调用模型服务提供方之前返回 429。

本指南介绍如何在 API Key 和模型上配置限制、验证限制是否生效,以及选择共享计数器存储。AISIX Cloud 和开源 AISIX 网关通过不同的管理路径提供相同能力。

准备工作​

开始前,请准备以下内容:

导出用于验证本页任一示例的网关请求参数:

# AISIX_PROXY 不含尾部斜杠或端点路径
# 本地快速入门使用 http://127.0.0.1:3000。
export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL"
export AISIX_MODEL="gpt-4o-prod"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"

对于 AISIX Cloud 示例,还需导出控制平面连接参数及待限制资源的 ID:

# AISIX_CP 包含 /api,且不含尾部斜杠
# 本地私有化部署快速入门使用 http://localhost:8080/api
export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
# API_KEY_ID 标识明文值为 AISIX_API_KEY 的调用方 Key。
export API_KEY_ID="YOUR_CALLER_API_KEY_ID"
# MODEL_ID 标识别名为 AISIX_MODEL 的模型。
export MODEL_ID="YOUR_MODEL_ID"

选择限流配置方式​

可以通过两种方式配置限流:

  • 把 rate_limit 块直接关联到调用方 API Key 或模型。当某个应用或租户需要独立配额时使用调用方限制;当某个别名的所有调用方应共享配额时使用模型限制。
  • 当需要单独管理的配额、条件匹配,或需要为团队、成员、API Key、模型或模型服务提供方创建独立配额桶时,请创建限流策略。

调用方 API Key 还可以为其调用的每个 MCP 服务器设置单独的请求数和并发限制。参见 MCP 限流与预算。

每个匹配的限制都会生效。例如,一个请求可以同时占用调用方 API Key、解析后的模型、团队策略和成员策略中的容量。只有所有匹配的配额桶都有剩余容量,请求才会继续。

配置调用方 API Key 限制​

以下示例把一个调用方 API Key 限制为每分钟一次请求。

AISIX Cloud​

在控制台中打开 API keys,展开调用方 API Key,然后使用其中的 Rate limits 控件。Admin API 为自动化提供相同配置能力。

更新调用方 API Key,为其设置每分钟一次请求的限制:

curl -sS -X PATCH "${AISIX_CP}/environments/${ENV_ID}/api_keys/${API_KEY_ID}" \
-H "Authorization: Bearer ${AISIX_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"rate_limit": {
"rpm": 1
}
}'

更改会自动投射到已接入的网关。

开源 AISIX 网关​

替换现有调用方 API Key 条目以添加相同限制。保留其当前的 display_name、key_env 和 allowed_models 值:

resources.yaml(调用方限流)
api_keys:
- display_name: chat-app
key_env: CALLER_API_KEY
allowed_models:
- gpt-4o-prod
rate_limit:
rpm: 1

让验证命令可以访问调用方凭证:

# 使用与验证请求相同的明文值。
export CALLER_API_KEY="${AISIX_API_KEY}"

如果 AISIX 安装在主机上,请在重新加载网关之前验证完整资源文件:

aisix validate --resources resources.yaml

对于开源快速入门中的 Docker 环境,请使用基于容器的验证和重新加载命令。快速入门已让容器可以访问 CALLER_API_KEY。

配置模型限制​

当某个别名的所有调用方都应共享同一配额时,请使用模型限制。以下示例允许使用 gpt-4o-prod 的所有调用方 API Key 每分钟总计发送一次请求。

AISIX Cloud​

在控制台中打开 Models,编辑模型,然后使用 Rate limits 字段。Admin API 为自动化提供相同配置能力。

更新模型:

curl -sS -X PATCH "${AISIX_CP}/environments/${ENV_ID}/models/${MODEL_ID}" \
-H "Authorization: Bearer ${AISIX_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"rate_limit": {
"rpm": 1
}
}'

开源 AISIX 网关​

在直接模型条目中添加限制,并保留已有的模型服务提供方和密钥设置:

resources.yaml(模型限流)
models:
- display_name: gpt-4o-prod
provider: openai
model_name: gpt-4o
provider_key: openai-prod
rate_limit:
rpm: 1

验证完整资源文件并重新加载网关。此后,使用不同调用方 API Key 的请求会从同一个模型配额桶中扣减容量。

验证限流​

前面的调用方和模型示例都使用每分钟一次请求的限制。请一次只配置并测试一个直接限制,以便 429 响应能明确指向所测试的限制。也可以用相同的请求序列验证限流策略。

等待 AISIX Cloud 更改到达网关,或重新加载开源资源文件后,发送三个请求:

for i in 1 2 3; do
printf "request %s: " "${i}"
curl -sS -o /dev/null -w "%{http_code}\n" -X POST "${AISIX_PROXY}/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<EOF
{
"model": "${AISIX_MODEL}",
"messages": [
{
"role": "user",
"content": "Hello from AISIX."
}
]
}
EOF
done

第一个请求应到达上游模型。同一固定窗口内的其余请求应超过限制:

request 1: 200
request 2: 429
request 3: 429

兼容 OpenAI 的限流拒绝会返回 429 Too Many Requests,并使用代理错误格式:

{
"error": {
"message": "request limit exceeded (requests)",
"type": "rate_limit_exceeded"
}
}

来自调用方 API Key 限制、模型限制或限流策略的拒绝,都会带上 Retry-After,以及 X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset 和 X-RateLimit-Scope,它们描述的是拒绝该请求的那一条限制:

retry-after: 43
x-ratelimit-limit: 1
x-ratelimit-remaining: 0
x-ratelimit-reset: 43
x-ratelimit-scope: rpm

请求计数和 Token 限制的拒绝向其固定窗口的结束时刻倒数。并发拒绝没有窗口——并发槽位在某个在途请求结束时释放——因此固定返回 60 秒的提示。成功的 Chat Completions 响应携带的是另一组按维度拆分的响应头。参见限流拒绝响应头。

限流字段与计数器行为​

调用方 API Key 和模型别名使用相同的 rate_limit 字段。每个字段都是可选的;省略某个字段时,AISIX 不会执行相应维度的限制。

字段限制固定窗口
rps每秒请求数1 秒
rpm每分钟请求数60 秒
rph每小时请求数3,600 秒
rpd每日请求数86,400 秒
tpm每分钟 Token 数60 秒
tpd每日 Token 数86,400 秒
concurrency进行中的请求数无窗口

AISIX 在处理请求的不同时点检查并记录三种限制维度:

维度AISIX 检查时点AISIX 记录用量时点
请求计数调用模型服务提供方之前在调用前检查期间;较早匹配的层可能已增加计数,随后请求才被较晚的层拒绝
Token调用模型服务提供方之前,依据当前窗口中已记录的 Token上游响应报告用量之后
并发调用模型服务提供方之前持有到响应或流结束,然后释放

Token 限制包含提示词和生成结果 Token。对于 Anthropic 流量,还包含 Anthropic 与输入 Token 分开报告的提示词缓存创建和缓存读取 Token。OpenAI 缓存 Token 已包含在提示词 Token 中,因此 AISIX 不会重复计数。

由于模型服务提供方在生成响应后才报告用量,跨过 Token 限制的请求可能成功完成。它的 Token 用量可能耗尽当前窗口,导致后续请求被拒绝。

只有上游响应报告的 Token 用量才会增加 Token 计数器。部分媒体调用不报告 Token 用量,因此不会增加 tpm 或 tpd:whisper-1 的转录和翻译、所有文本转语音请求、dall-e-2 和 dall-e-3 的图像生成与编辑,以及视频请求。报告 Token 用量的模型(例如 gpt-4o-transcribe 和 gpt-image-1)照常计数。音频时长仅用于费用计算,不计入 Token 限制。无论调用哪个端点,只要适用的 tpm 或 tpd 窗口已经耗尽,即使该调用不会增加 Token,也仍会被拒绝。

直接关联到调用方 API Key 或模型的 Token 限制只支持分钟和日窗口,这些资源没有每秒或每小时 Token 字段。经典限流策略也会使用分钟和日窗口执行 Token 上限。AISIX Cloud 会拒绝使用秒或小时窗口的 Token 上限。对于开源 AISIX 网关,资源 Schema 虽接受这些配置,但运行时不会执行相应上限。

模型限制的应用方式​

如果请求同时匹配调用方限制和模型限制,AISIX 会在两个配额桶中预留容量。任一配额桶耗尽都会拒绝请求。

当直接模型作为路由模型或语义路由的目标时,模型限制同样适用。路由分发会跳过超出自身限制的目标并继续尝试其余目标;所有目标都超出限制时,请求返回 429。语义分发会执行所选目标的限制;该目标没有容量时返回 429。对同一模型的直接请求和路由请求共享其限制配额桶。

inject 模式的透传路由也可以预留模型限制。当请求正文通过别名或服务提供方原生名称,指定了路由中服务提供方密钥所属服务提供方的某个模型时,AISIX 会预留模型限制。匹配的模型与建模路由共享请求计数和并发限制配额桶;forward_client 路由从不查询模型探测器。调用方层级的请求计数和并发限制适用于每条路由。

适用的 tpm 或 tpd 窗口若已耗尽,仍会拒绝透传请求。但是,即使 AISIX 识别出受支持的信封,并在请求的用量事件中记录了 Token 用量,透传用量也不会增加这些 Token 计数器。

选择限流计数器存储​

网关启动配置决定限流计数器是某个进程本地独享,还是由多个网关实例共享。此设置同时适用于直接关联到资源的限制和该网关执行的可复用策略。

后端计数器作用域适用场景
Memory(默认)单个网关进程由单实例执行限制,或可接受每个实例分别计算配额。
Redis使用同一 Redis 后端的所有网关实例部署必须执行同一个共享请求数、Token 或并发配额。

使用 Memory 后端时,每个网关实例只统计自己处理的流量。因此,在流量均匀分发的多实例部署中,一个窗口内总体放行的流量可能超过所配置的单进程限制。固定路由可以减少同一调用方或租户的这种差异,但 Redis 才是共享计数器方案。

当多个网关实例必须执行同一配额时,请配置 Redis:

config.yaml
ratelimit:
backend: redis
redis:
mode: single
url: redis://127.0.0.1:6379/

当 ratelimit.backend 为 redis 时,网关要求提供 ratelimit.redis 块,缺少该块时启动会失败。启动时连不上 Redis 则不再导致启动失败:网关会绑定监听端口并开始服务,按副本计数,并输出一条 WARN 日志,点明后端、Redis 的主机和端口,以及本次连接所花掉的预算。日志永远不会输出所配置的 URL,因为其中带有密码。该降级状态每 5 分钟重述一次,同时后台任务会在 Redis 恢复应答后立即接入共享后端。网关不会永久切换到 memory 后端;降级期间不执行集群级限流。

只有网关在任何网络交互之前就拒绝的配置才会导致启动失败:无法解析的 url、无法读取或无法解析的 TLS 材料,以及该配置块自身的校验——所选模式缺少 url、nodes、sentinels 或 master_name,以及 timeout_secs: 0。Redis 明确应答并拒绝连接配置时走的是降级路径,包括凭据被拒绝、服务端返回 NOAUTH 或 DENIED,以及服务端没有所配置的 database。此时告警带的是 reason=refused 而不是 reason=unreachable,每 5 分钟的重述也带同一个词。网关会持续尝试重新接入,因此在 Redis 一侧修好凭据后无需重启即可采用它。

无论 Redis 中断是在网关启动时就已存在,还是启动之后才发生,限流都会降级为进程本地计数器。请求仍受各进程限制保护,但中断期间部署不会执行统一的集群级配额。中断期间的计数不会复制回 Redis,因此恢复后,在当前活动窗口结束之前,各计数器可能仍不一致。

ratelimit.redis.timeout_secs 决定网关在把请求交给上述失败即放行路径之前会等待多久,默认值为 5 秒,最小值为 1,取 0 会在启动时被拒绝并点名该字段。Redis 恢复应答后,共享计数会自动恢复。

timeout_secs 约束的是单次 Redis 往返或连接尝试,也包括网关在启动时建立的那次连接;一旦有一次失败,该子系统接下来所做的一切都会在 30 秒内直接短路,而不是再等一次,其中缓存的精确连接和向量连接算作同一个子系统,限流器是另一个。这 30 秒冷却期的长度被设定为足以覆盖一次上游调用,因为一个请求的缓存读取和缓存写入分别位于该调用的两侧;因此一个请求为缓存付出一次预算、为限流器付出一次预算,而不是每个 Redis 操作各付一次——上游环节耗时超过 30 秒的请求,仍可能在写入时再付出一份预算。在 cluster 和 sentinel 模式下,建立连接并不是一次往返,这份预算会按每个已配置的端点一份、再加走完之后最终连上的那个节点一份计。因此这两种模式下整次连接的预算是 timeout_secs 乘以(已配置端点数 + 1),该乘积同样约束启动时建立的连接。

决定冷却期何时结束的是一个后台任务,而不是业务请求:30 秒到期时它向 Redis 发送一次 PING,成功则关闭短路,失败则重新计时 30 秒。在它关闭短路之前,请求会继续直接短路返回,因此没有任何请求需要付出超时代价去探测 Redis 是否仍不可用。恢复速度不变——Redis 恢复应答后,短路仍会在一个冷却期之内解除。

使用 Redis 的并发槽位会在请求完成时释放。concurrency_ttl_secs 用于回收实例崩溃或请求中断后遗留的槽位,默认值为 300 秒。

Redis 连接模式​

ratelimit.redis.mode 字段用于选择 Redis 部署类型,并决定必须提供哪些连接字段。前面的示例使用带单个 url 的 single 模式。

对 Redis Cluster 种子节点使用 cluster:

config.yaml
ratelimit:
backend: redis
redis:
mode: cluster
nodes:
- redis://10.0.0.1:6379/
- redis://10.0.0.2:6379/

对由 Sentinel 管理的主节点使用 sentinel:

config.yaml
ratelimit:
backend: redis
redis:
mode: sentinel
sentinels:
- redis://10.0.0.1:26379/
- redis://10.0.0.2:26379/
master_name: mymaster

各模式必需的字段如下:

模式必需连接字段
singleurl
cluster一个或多个 nodes 条目
sentinel一个或多个 sentinels 条目及 master_name

Redis 需要身份认证时,请设置 username 和 password。这两个字段在所有模式下都生效,并且会覆盖内嵌在 url 中的凭据,因此通过环境变量提供的取值不会被 URL 里遗留的旧凭据压过。请把它们作为一对来设置:只设置其中一半会同时替换两半,因为从两个来源拼出的登录信息在任何一处都不存在。database 在 single 和 sentinel 模式下生效;Redis Cluster 只有 DB 0。在 Sentinel 模式中,Sentinel 节点凭证写在 Sentinel URL 中,而 username、password 和 database 应用于发现到的 Redis 主节点。

故障排除​

先确定被拒绝请求的作用域,再找出所有可能匹配它的限制。

现象检查项
已配置的限制未生效。对于 AISIX Cloud,确认更改已投射到网关。对于开源网关,确认资源文件已重新加载。然后验证请求使用了预期的调用方 API Key 和模型。
请求在尚未达到预期调用方限制时被拒绝。检查是否存在匹配该 API Key、模型、团队、成员或模型服务提供方的模型限制和限流策略。每个匹配层都必须通过。
多个网关实例的总体流量超过配置限制。检查 ratelimit.backend。Memory 后端在每个进程中维护独立计数器;如需统一共享配额,请使用 Redis。
受 Token 限制的请求成功,但下一个请求被拒绝。这是成功响应耗尽剩余 Token 容量时的预期行为。Token 用量会在模型服务提供方报告后记录。

后续步骤​

当直接调用方限制和模型限制不够灵活时,请配置限流策略。继续配置响应缓存以复用符合条件的 Chat Completions 响应,或查看指标以监控限流拒绝。