API Key 与模型限流
限流可以保护模型服务提供方容量,并防止单个调用方或模型耗尽共享配额。当配额属于某个调用方时,请在调用方 API Key 上配置限制;当使用某个模型的所有调用方应共享配额时,请在模型上配置限制。
这些限制属于其所配置的 API Key 或模型。限流策略是独立规则,可以匹配团队、成员、API Key、模型、模型名称或模型服务提供方,并把匹配流量划分到彼此独立的配额桶中。同一请求可以同时匹配 API Key 限制、模型限制和策略。每个匹配的限制都会生效;只要有任一配额桶耗尽,网关就会在调用模型服务提供方之前返回 429。
本指南介绍如何在 API Key 和模型上配置限制、验证限制是否生效,以及选择共享计数器存储。AISIX Enterprise 或 AISIX Cloud 使用控制面路径,开源 AISIX 网关使用资源文件路径。两种路径配置相同的网关能力。
准备工作
开始前,请准备以下内容:
- 可以发送代理请求的模型别名和调用方 API Key。如果尚未配置,请参阅模型服务提供方密钥、模型别名和调用方 API Key。
- 对于 AISIX Enterprise 或 AISIX Cloud:已接入网关的 环境,以及具有写权限范围的 Admin Token。可以按照 AISIX Enterprise 快速入门进行本地评估;如需申请 AISIX Cloud 访问权限,请联系 API7。
- 对于开源 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"
对于控制面示例,还需导出控制面连接参数及待限制资源的 ID:
# AISIX_CP 包含 /api,且不含尾部斜杠
# 本地 AISIX Enterprise 快速入门使用 http://localhost:8080/api
export AISIX_CP="YOUR_AISIX_CONTROL_PLANE_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 Enterprise 或 AISIX Cloud
在控制台中打开 API 密钥,展开调用方 API Key,然后使用其中的 限流 控件。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 值:
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 Enterprise 或 AISIX Cloud
在控制台中打开 模型,编辑模型,然后使用 限流(可选) 字段。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 网关
在直接模型条目中添加限制,并保留已有的模型服务提供方和密钥设置:
models:
- display_name: gpt-4o-prod
provider: openai
model_name: gpt-4o
provider_key: openai-prod
rate_limit:
rpm: 1
验证完整资源文件并重新加载网关。此后,使用不同调用方 API Key 的请求会从同一个 模型配额桶中扣减容量。
验证限流
前面的调用方和模型示例都使用每分钟一次请求的限制。请一次只配置并测试一个直接限制,以便 429 响应能明确指向所测试的限制。也可以用相同的请求序列验证限流策略。
等待控制面更改到达网关,或重新加载开源资源文件后,发送三个请求:
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
分钟窗口在每个 UTC 整分重置,因此跨过整分边界的一组请求中,后面的请求可能成功。
兼容 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 限制的拒绝向下一个窗口边界倒数,例如整分时刻,日限额则是 00:00 UTC。使用 window_type: sliding 时,则改为倒数到足够的用量移出滚动窗口的时刻。并发拒绝没有窗口——并发槽位在某个在途请求结束时释放——因此固定返回 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 | 进行中的请求数 | 无窗口 |
在默认的 window_type: fixed 下,每个带窗口的字段都按固定窗口计数,窗口按 UTC 时钟对齐,而不是从调用方的第一个请求开始。计数在每个边界整体清零:rps 每秒,rpm 和 tpm 在每个整分,rph 在每个整点,rpd 和 tpd 在 00:00 UTC,即北京时间 08:00。由于整个计数一次清零,一个窗口末尾的突发和下一个窗口开头的突发合计,可以在一个窗口长度内放行到约 2 倍限额。例如设置 rpm: 100 时,10:00:50 的 100 个请求和 10:01:05 的另外 100 个请求都会被放行。如需限制任意一个窗口长度的区间,请使用滑动窗口。
AISIX 在处理请求的不同时点检查并记录三种限制维度:
| 维度 | AISIX 检查时点 | AISIX 记录用量时点 |
|---|---|---|
| 请求计数 | 调用模型服务提供方之前 | 在调用前检查期间。较晚的层拒绝请求时,较早的层已增加的计数会退还;参见请求如何计数 |
| Token | 调用模型服务提供方之前,只依据当前窗口中已记录的 Token,不为请求预留用量 | 响应完成之后,依据上游报告的用量 |
| 并发 | 调用模型服务提供方之前 | 持有到响应或流结束,然后释放 |
Token 限制包含提示词和生成结果 Token。对于 Anthropic 流量,还包含 Anthropic 与输入 Token 分开报告的提示词缓存创建和缓存读取 Token。OpenAI 缓存 Token 已 包含在提示词 Token 中,因此 AISIX 不会重复计数。
由于模型服务提供方在生成响应后才报告用量,AISIX 要等请求完成才记录其 Token。放行时只检查已记录的 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 Admin API 会拒绝使用秒或小时窗口的 Token 上限。对于开源 AISIX 网关,资源 Schema 虽接受这些配置,但运行时不会执行相应上限。
Token 限制的超额
已记录的用量达到 Token 限制后,AISIX 会拒绝新请求,但已放行的请求仍会全部完成并计入用量。因此在并发场景下,超额不止跨过限制的那一个请求,大约是达到 限制时的在途请求数乘以单个请求的最大 Token 用量。
例如,在途请求有 10 个,每个最多使用 40 Token,用量可能超出 tpm 限制约 400 Token。
在途请求数的统计范围取决于计数器后端:
- 使用 Redis 时,按共享同一后端的所有网关实例统计在途请求数。
- 使用内存后端时,每个实例只统计自己处理的流量,因此超额还要再乘以实例数。限制本身也是按实例生效的,参见选择限流计数器存储。
concurrency 限制可以约束在途请求数,从而减小超额。它会以 429 拒绝超出的请求,而不是让请求排队。
AISIX 不提供严格的 Token 上限。上述数字可用于估算限制的取值,但不是保证。
选择窗口类型
window_type 决定分钟、小时和日限制(rpm、tpm、rph、rpd 和 tpd)如何计数。取值为 fixed(默认)或 sliding。它不影响 rps 和 concurrency。
可以在以下位置设置 window_type:
- 调用方 API Key 的
rate_limit。 - 调用方 API Key 的
mcp_rate_limits中的每个服务器条目,作用于rpm、rph和rpd。 - 模型的
rate_limit。 - 条件限流策略的
limits。
经典限流策略使用 window 加 max_requests 或 max_tokens,始终按固定窗口计数,不接受 window_type。
fixed 窗口在每个 UTC 边界重置,详见限流字段与计数器行为。sliding 窗口用固定步长的子桶记录用量,并按覆盖一整个窗口的子桶之和判定每个请求:
| 字段 | 窗口 | 子桶步长 |
|---|---|---|
rpm、tpm | 60 秒 | 10 秒 |
rph | 3,600 秒 | 5 分钟 |
rpd、tpd | 86,400 秒 | 1 小时 |
任意一个窗口长度的区间内,放行的请求数都不会超过请求数限额。Token 限制对同一求和值只按已记录的用量检查,因此在途请求仍可能造成超额,参见 Token 限制的超额。代价是粒度:用量最多比窗口长度晚一个步长才移出统计。例如,10:00:03 记录的一个 rpm 请求在 10:01:10 才不再计数。
两者的区别体现在窗口边界上。设置 rph: 10 时,假设调用方在 10:55 到 10:59 之间发送 10 个请求,从 11:00 起再发送 10 个:
- 使用
fixed时,小时计数在 11:00 清零,因此 20 个请求在大约十分钟内全部放行,接近 2 倍限额。 - 使用
sliding时,11:00 的计数仍包含 10:55 起的请求,因此第二段突发会被拒绝,直到这些请求移出窗口。
在 fixed 和 sliding 之间切换后,计数从零开始。
限流响应头按以下方式反映滑动窗口的状态:
- 滑动窗口限制拒绝请求时,
Retry-After和X-RateLimit-Reset给出请求可被放行前的精确等待时间,单位为整秒,向上取整,最小为 1。 - 对于
tpm和tpd,给出的是累计用量降到限额以下所需的等待时间,因为被拒请求自身的 Token 数尚不可知。 - 同时设置了多个限制时,响应头给出的是拒绝该请求的那一项限制的等待时间。
- 在成功的 Chat Completions 响应中,
x-ratelimit-reset-requests和x-ratelimit-reset-tokens表示当前计数全部移出窗口所需的时间。
在 AISIX Enterprise 和 AISIX Cloud 中,fixed 不会被存储,也不会由 Admin API 返回;省略该字段即视为 fixed。如果一个限制没有设置 rpm、tpm、rph、rpd 或 tpd 中的任何一项,控制面也会丢弃其中的 sliding,因为它不会改变任何行为。在 AISIX OSS 中,资源文件接受该字段,但它只影响上述五个维度。
先升级网关再启用滑动窗口
sliding 需要 AISIX 网关 1.10.0 或更高版本。更旧的网关会忽略该字段,继续按固定窗口计数;共享 Redis 计数器的不同版本网关会各自计数,合计可能超过限额。为避免这种情况,只要目标环境中有已注册的网关运行早于 1.10.0 的版本,AISIX Enterprise 和 AISIX Cloud 就会以 422 DP_INCOMPATIBLE 拒绝保存 sliding。
在这期间,任何已含 sliding 的调用方 API Key、模型或限流策略的保存都会被拒绝,包括禁用或轮换调用方 API Key;删除不受影响。请先把环境中的所有网关升级到 1.10.0 或更高版本,再启用滑动窗口。
配置滑动窗口
在控制台中,以下四处表单提供 窗口类型 控件,选项为 固定窗口 和 滑动窗口:
- API 密钥 页面:调用方 API Key 的 限流 控件,以及 按 MCP 服务器限流 中每个服务器的限额。
- 模型 页面:模型的 限流(可选) 字段。
- 限流 页面:条件策略的 限额 区域。
表单中至少设置一个分钟、小时或日限制后,该控件才可用。
自动化场景下,在设置限额的同时设置 window_type。以下请求为调用方 API Key 设置每小时 10 个请求的滑动窗口限制:
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": {
"rph": 10,
"window_type": "sliding"
}
}'
对于开源 AISIX 网关,在资源文件的对应条目中添加同一字段:
api_keys:
- display_name: chat-app
key_env: CALLER_API_KEY
allowed_models:
- gpt-4o-prod
rate_limit:
rph: 10
window_type: sliding
模型限制的应用方式
如果请求同时匹配调用方限制和模型限制,AISIX 会把它计入 两个配额桶的请求数和并发限制。任一配额桶耗尽都会拒绝请求。两个配额桶都不预留 Token,参见 Token 限制的超额。
当直接模型作为路由模型或语义路由的目标时,模型限制同样适用。每次分发到该目标的尝试都会计入其限制,详见请求如何计数。路由分发会跳过超出自身限制的目标并继续尝试其余目标;所有目标都超出限制时,请求返回 429。语义分发会执行所选目标的限制;该目标没有容量时返回 429。对同一模型的直接请求和路由请求共享其限制配额桶。
inject 模式的透传路由也可以预留模型限制。当请求正文通过别名或服务提供方原生名称,指定了路由中服务提供方密钥所属服务提供方的某个模型时,AISIX 会预留模型限制。匹配的模型与建模路由共享请求计数和并发限制配额桶;forward_client 路由从不查询模型探测器。调用方层级的请求计数和并发限制适用于每条路由。
适用的 tpm 或 tpd 窗口若已耗尽,仍会拒绝透传请求。但是,即使 AISIX 识别出受支持的信封,并在请求的用量事件中记录了 Token 用量,透传用量也不会增加这些 Token 计数器。
请求如何计数
AISIX 对请求执行重试或故障转移时,会多次访问模型服务提供方。一项限制按调用 方发出的下游请求计数,还是按每次上游尝试计数,取决于这项限制属于谁。
以下限制对每个下游请求只计一次,不论后续发生多少次重试或故障转移:
- 调用方 API Key 自身的限制。
- 调用方所寻址模型的限制。请求模型组时,计入的是模型组自身的
rate_limit,而不是其成员的限制。 - 不依赖模型组成员的限流策略,包括不论成员自身的
model、model_name和provider是什么,模型组自身的 ID 或别名都能满足其条件的条件策略,详见设置限制。 - 调用方 API Key 上的 MCP 服务器限制。
请求直接模型时,即使 AISIX 进行了重试,也只在该模型的限制中计一次。
模型组成员自身的容量按分发到该成员的每次上游尝试计数,同一目标的重试也计入,所有经模型组路由的端点都是如此。这包括成员自身的 rate_limit、该成员上的经典模型作用域策略,以及命中条件或配额桶依赖该成员的条件策略。超出自身限制的成员会被跳过,AISIX 继续尝试下一个目标。
例如,一个请求模型组的请求,第一个成员失败后在该成员上重试一次,再由第二个成员成功响应。这个请求在调用方 API Key 和模型组自身的限制中各计一次,在第一个成员的限制中计两次,在第二个成员的限制中计一次。
在任何尝试到达上游之前就被网关自身限流拒绝的请求,在任何一层都不消耗额度。某一层拒绝请求时,AISIX 会退还其他层已为该请求增加的计数 。模型组请求因所有成员都超出自身限制而返回 429、且没有任何尝试发送到上游时,调用方 API Key、模型组自身的限制和请求级策略同样不计数。
真正发送到上游的尝试总会计数,不论上游返回什么,包括 5xx 和上游返回的 429。它所属的请求也一样:较早的尝试已发送到上游、随后最后一个目标被自身限制拒绝时,请求保留已计入的次数。如果退还之前计数所在的窗口已经滚动,或退还时无法连接 Redis,计数也会保留。
Token 限制对每个请求只计一次,使用实际响应该请求的那次尝试的用量。
请求日志也体现了这一区别。在控制台的日志页面,发生重试或故障转移的请求每次尝试显示一行,与成员计数器一致。勾选每个请求只看最后一条后,每个下游请求只显示一行,参见每个请求只看最后一条。
选择限流计数器存储
网关启动配置决定限流计数器是某个进程本地独享,还是由多个网关实例共享。此设置同时适用于直接关联到资源的限制和该网关执行的可复用策略。
| 后端 | 计数器作用域 | 适用场景 |
|---|---|---|
| Memory(默认) | 单个网关进程 | 由单实例执行限制,或可接受每个实例分别计算配额。 |
| Redis | 使用同一 Redis 后端的所有网关实例 | 部署必须执行同一个共享请求数、Token 或并发配额。 |
使用 Memory 后端时,每个网关实例只统计自己处理的流量。因此,在流量均匀分发的多实例部署中,一个窗口内总体放行的流量可能超过所配置的单进程限制。固定路由可以减少同一调用方或租户的这种差异,但 Redis 才是共享计数器方案。
当多个网关实例必须执行同一配额时,请配置 Redis:
ratelimit:
backend: redis
redis:
mode: single
url: redis://127.0.0.1:6379/
当 ratelimit.backend 为 redis 时,网关要求提供 ratelimit.redis 块,缺少该块时启动会失败。启动时连不上 Redis 不会再导致启动失败,但有界的启动连接尝试可能延迟所有监听器。尝试结束后,Redis 不再阻止监听器启动;网关会输出一条 WARN 日志,点明后端、配置的端点值、原因和连接错误。代理监听器可用后,网关按副本计数。该告警每 5 分钟重述一次,同时后台任务会在 Redis 恢复应答后立即接入共享后端。网关不会永久切换到 memory 后端;降级期间不执行集群级限流。
告警会逐字记录配置的端点值:single 模式下的 url、cluster 模式下的 nodes,以及 sentinel 模式下的 sentinels。嵌入这些值中的凭据也会被记录。请使用单独的 username 和 password 字段配置数据节点凭据。Sentinel 节点凭据仍包含在 Sentinel URL 中,因此请限制对网关日志的访问。
无法在后台恢复的本地配置和解析错误会导致启动失败,包括:无法解析的 url;AISIX 无法 读取或解析的 TLS 材料;仅配置客户端证书或密钥之一;ratelimit.concurrency_ttl_secs: 0;所选模式缺少 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 秒内直接短路,而不是再次等待;Redis 服务端返回的错误只会让当前操作失败,不会打开短路。缓存的精确连接和向量连接算作同一个子系统,限流器是另一个。这 30 秒冷却期足以覆盖一次上游调用,因为请求的缓存读取与写入位于调用两侧;因此一个请求为缓存付出一次预算、为限流器付出一次预算,而不是为每 个 Redis 操作各付一次。上游环节耗时超过 30 秒的请求仍可能在写入时再付出一份预算。在 cluster 和 sentinel 模式下,网关以 timeout_secs ×(已配置端点数 + 1)作为整个启动拓扑遍历的总预算。该乘积限制整次启动连接,而不是其中每次尝试;每次尝试仍受单个 timeout_secs 限制。single 模式下,整个启动连接只有一个 timeout_secs 预算。
决定冷却期何时结束的是一个后台任务,而不是业务请求:30 秒到期时它向 Redis 发送一次 PING,成功则关闭短路,失败则重新计时 30 秒。在它关闭短路之前,请求会继续直接短路返回,因此没有任何请求需要付出超时代价去探测 Redis 是否仍不可用。Redis 恢复可达后,恢复过程仍可能需要超过一个冷却窗口。
本地并发槽位会在请求完成时释放。SSE 中继会保留每个匹配的槽位,直到响应体关闭或被取消。Redis 支持的中继会在 Redis 可达时续约每个活跃租约。过期槽位在 concurrency_ttl_secs 之后被回收,该值默认为 300 秒。如果 Redis 报告某个活跃租约已不存在,AISIX 会结束透传 SSE 中继。
在混合版本发布期间,应根据旧版副本保持每个流预留的方式处理。如果旧版副本在流的整个生命周期中保留预留,但无法续约,请将 ratelimit.concurrency_ttl_secs 设为长于最长可能预留时间的值,其中包括等待上游响应头和流的生命周期。更长的 TTL 也会延迟回收因副本崩溃而遗留的槽位。
透传 SSE 需要不同的发布方式。旧版副本如果在返回响应头时释放透传预留,则无法靠延长 TTL 来保护。在新版副本开始执行共享限制前,请先停止向这些旧版副本发送新的透传 SSE 请求。旧版副本上已存在的透传流在结束或被终止前,仍不计入该并发数。
Redis 连接模式
ratelimit.redis.mode 字段用于选择 Redis 部署类型,并决定必须提供哪些连接字段。前面的示例使用带单个 url 的 single 模式。
对 Redis Cluster 种子节点使用 cluster:
ratelimit:
backend: redis
redis:
mode: cluster
nodes:
- redis://10.0.0.1:6379/
- redis://10.0.0.2:6379/
对由 Sentinel 管理的主节点使用 sentinel:
ratelimit:
backend: redis
redis:
mode: sentinel
sentinels:
- redis://10.0.0.1:26379/
- redis://10.0.0.2:26379/
master_name: mymaster
各模式必需的字段如下:
| 模式 | 必需连接字段 |
|---|---|
single | url |
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 Enterprise 或 AISIX Cloud,确认更改已投射到网关。对于开源网关,确认资源文件已重新加载。然后验证请求使用了预期的调用方 API Key 和模型。 |
| 请求在尚未达到预期调用方限制时被拒绝。 | 检查是否存在匹配该 API Key、模型、团队、成员或模型服务提供方的模型限制和限流策略。每个匹配层都必须通过。 |
| 多个网关实例的总体流量超过配置限制。 | 检查 ratelimit.backend。Memory 后端在每个进程中维护独立计数器;如需统一共享配额,请使用 Redis。 |
| 模型组成员的限制比按请求数预期的更早耗尽。 | 成员发生重试或承接故障转移时,这是预期行为:成员自身的限制计入分发给它的每次尝试,而调用方 API Key 和模型组自身的限制对每个请求只计一次。参见请求如何计数。 |
| 受 Token 限制的请求成功,但下一个请求被拒绝,或用量超过限制。 | 这是成功响应耗尽剩余 Token 容量时的预期行为。Token 用量会在模型服务提供方报告后记录,因此达到限制时的在途请求仍会完成并计入用量。参见 Token 限制的超额。 |
后续步骤
当直接调用方限制和模型限制不够灵活时,请配置限流策略。继续配置响应缓存以复用符合条件的 Chat Completions 响应,或查看指标以监控限流拒绝。