HIGH CONCURRENCY × LLM GATEWAY

高并发场景下,如何解决 LLM 接口限流?

解决思路不是“把 429 重试成功”,而是把 Provider 的 请求数、Token 吞吐和在途连接建模为有限容量,在请求真正发出前完成准入、调度、削峰与降级。429 只应当是本地预测偏差的最后反馈。

RPM / TPM / 并发槽Token-aware AdmissionRedis 原子配额有界优先级队列Retry BudgetBrownout

1. 429 不是普通网络失败:它会触发重试风暴

低流量时,“休眠几秒再重试”偶尔有效。高并发时,大量实例会在相近时刻重试,失败流量继续消耗额度,导致 429 从局部问题扩散为排队、超时和全链路雪崩。

错误路径 多层各自重试

业务层 × SDK × Gateway × 队列消费者都重试 3 次,最坏会把一次请求放大为 3⁴ = 81 次 出站尝试。

Provider
429
初始请求同步重试回流

正确路径 出站前先调度

一个统一 Gateway 保有全局预算账本。能同时获得 RPM、Token 和并发槽的请求才出站;否则按 Deadline 进入队列、降级、切路由或快速失败。

入口:请求/租户限流

先隔离 noisy neighbor,保护公共容量。

准入:原子获取多维预算

输入 Token + 预留输出 Token + 请求额度 + 并发槽。

调度:按优先级与 Deadline 处理

排队只削峰,不制造容量;过期任务直接处理掉。

反模式:扩 Pod、增加 Worker 或轮换同组织 API Key,通常不会增加 Provider 的组织级共享配额;它们只会让你更快撞上同一个上游限制。

2. LLM 容量模型:同时受四种资源约束

普通 HTTP 接口常只看请求数;LLM 的一条长上下文、长流式回答可能占用数万个 Token 和几十秒连接。可持续速率取四个上界中的最小值。

RPM
请求频率

大量短问答最容易先耗尽。每一次真正发出调用,通常不退还。

INPUT TPM
输入 Token

长 Prompt、RAG 文档、历史对话造成的核心约束。

OUTPUT TPM
输出 Token

长生成、思考/推理、流式回答持续消耗吞吐。

IN-FLIGHT
在途并发

慢响应和长流式连接会长期占着并发槽。

safe_rps ≈ utilization × min( R / 60, TI / (60 × I), TO / (60 × O), C / S )

变量含义

R:RPM;TI / TO:输入 / 输出 TPM;I / O:平均输入 / 输出 Token;C:并发槽;S:平均耗时秒数。

为什么不能取 100%?

为 Token 长尾、突发流量、估算误差、故障切流留余量。生产上应看 P95/P99 Token 与延迟,不能只用平均值。

交互演示:没有准入 vs 有全局准入

点击模式,观察请求在“Provider 前”被如何处理。

LLM
Gateway
LLM
Provider
0到达
0出站
0429
0队列
0完成

3. 在 LLM Gateway 前完成全局准入

容量账本不能只放在每个 Pod 的内存里:10 个 Pod 各自认为还有一份配额,实际流量就会被放大 10 倍。使用 Redis + Lua 原子操作,或由中心调度器发放短周期额度租约。

统一 Gateway:把外部配额转化为可调度资源 业务 / Agent多实例并发到达 LLM Gateway ① 租户 / 用户限流 ② Token 估算 + 预占 ③ 调度 / 路由 / 降级 唯一的重试协调者 全局容量账本 Redis + Lua / 租约RPM Bucket输入 / 输出 Token BucketIn-flight Semaphore原子:要么全拿到,要么一个不占 Provider / Model / Region真实 usage / headers 反馈校准 usage、remaining、reset、429 → 反馈修正本地预测器
图 1 · Gateway 是容量控制面;Provider 响应是校准本地预测的权威反馈

Token 必须“预占 + 对账”

先用 tokenizer 计算输入 Token;输出按任务类型、历史分位数和 max_tokens 预留。调用完成后用真实 usage 对账:少用返还 Token 差额,超出则补扣并更新估算系数;流结束、取消、超时释放并发槽。

多资源要一次拿齐

不能 RPM 够了就先占请求额度、但 TPM 不够;也不能 Token 够了就提前占住并发槽等待。资源必须在同一原子事务中获取,否则会产生锁住资源却无法执行的死等。

4. 用计算器估算可持续速率

下面是容量规划的第一步:调节典型负载参数,观察是谁决定了系统上限。注意,这只是保守起点,线上还需用 P95/P99 和真实 headers 校准。

0.00安全 RPS
RPM 上限 RPS
输入 TPM 上限
输出 TPM 上限
并发上限

5. 队列只削峰,不能创造容量

短时峰值可以等待额度恢复;如果到达速率长期大于 Provider 放行速率,无限队列只会把“立即失败”变成“很久以后失败”,还会消耗内存、连接与用户耐心。

⏳ 有界 + Deadline

在线请求设置短 Queue Deadline。预计无法在时限内获得预算时,返回 429/503 + Retry-After,而不是无止境等待。

📬 同步转异步

报告、评测、清洗等可异步任务返回 task ID,写入持久化队列;任务过期要主动丢弃,不能“拿到额度才执行过期任务”。

↔ 公平调度

拆分在线 / 交互 / 离线 Lane,再按租户权重、优先级和 Token 成本用 WFQ 或 DRR 出队,避免长任务堵住短任务。

优先级 Lane + Token 成本公平调度进入 Gateway 的请求交互:短、Deadline 短核心:预留最小容量离线:大、可等待有界优先级队列交互 Lane:FIFO + 短 Deadline核心 Lane:保底配额离线 Lane:DRR / 批处理队头长任务不阻塞后续短任务调度器权重 + Token 成本+ Aging 防饥饿Provider平稳出站
图 2 · 排队的目标是吸收短时突发,并让有限容量按业务价值分配

6. 429 的正确处理:受控重试 + 自适应收缩

重试的准入条件

  • 只重试可恢复的 429、部分 5xx、网络瞬断;鉴权、参数错、余额不足、硬配额直接失败或切方案。
  • 优先遵循 Retry-After 与 reset headers;缺失时才采用 Full Jitter 指数退避。
  • 检查原始请求是否还剩足够 Deadline,且没有耗尽 Retry Budget。
  • 重试任务释放并发槽,进入延迟队列;不要原地 sleep 占着 Worker。

重试责任只能在一层

推荐 Gateway 成为唯一协调者:关闭或收紧 SDK 自动重试,业务层不再盲目补偿。对有外部副作用的 Agent 步骤,必须携带幂等键和步骤状态,避免重试间接导致重复发消息、下单或写库。

控制律:稳定成功时缓慢增加放行速率;429、TTFT 或 P99 恶化时快速降低并发(AIMD)。共享容量波动下,这通常比固定阈值更稳。

读取反馈

分类错误;读取 Retry-After / reset / remaining 与真实 usage。

判断预算

检查 Deadline、Retry Budget、幂等性与备用模型是否独立配额。

延迟重入

释放并发槽 → 延迟队列 → 到期后重新参与准入,而非直接冲上游。

7. 先减少需求,再讨论如何放行

最便宜的一次模型调用,是没有发生的那次。限流治理不只是在拥塞时“拦住请求”,更要减少请求数和 Token 消耗。

🗃️ 缓存与合并

精确缓存处理完全相同请求;语义缓存用于能容忍近似答案的场景;热点并发请求通过 Singleflight 合并在途调用,防止缓存击穿。

✂️ Token 优化

压缩 System Prompt、裁剪无关历史、长会话摘要、降低 RAG top_k、为不同任务设置合理的输出上限;固定前缀优先走 Provider Prompt Cache。

🤖 Agent 预算

一个入口可扇出 Planner、Worker、Judge 多次调用。为 Agent 设置最大步骤数、最大并行分支与总 Token Budget;Embedding、评测、离线摘要尽量批处理。

缓存的边界:缓存 key 至少要包含模型版本、Prompt 模板、采样参数、知识库版本和租户权限域。绝不能为提速让私有内容跨租户复用,也不能跳过权限与内容安全校验。

8. 路由与降级:围绕业务价值,而不是只看可用性

主模型紧张时,Router 根据复杂度、质量要求、剩余额度、延迟和成本选择小模型、其他区域或其他 Provider。前提是备用路径真正独立,并经过协议适配和回归评测。

Brownout 阶梯:容量越紧,越早关闭低价值工作正常请求质量与体验完整一级:减少调用关闭反思 / Judge禁用多候选生成缓存 / Singleflight二级:减 Token减少 RAG 文档缩短输出上限压缩上下文三级:切路由小模型备用区域/Provider转异步快速失败丢弃低价值安全、权限校验与高风险操作确认不随性能一起降级
图 3 · 预先定义、可观测、可回滚的 Brownout,比事故时临时“砍功能”可靠
核验“独立性”:不同 API Key、同组织不同模型、同模型不同 region 未必有独立配额;跨 Provider 还要验证 tokenizer、上下文长度、Tool Calling、JSON Schema、流式协议、安全策略和输出质量。

9. 用监控与压测闭环校准真实容量

必须按维度拆分的指标

  • Provider / 模型 / 区域 / 业务线 / 租户的 RPM、输入输出 TPM 利用率与剩余额度
  • Token 预占与实际 usage 的偏差、in-flight、TTFT、完整延迟、P95/P99
  • 队列深度、最老任务年龄、过期丢弃数、拒绝率与 Retry-After
  • 429 原因、重试放大系数、熔断状态、Fallback / 降级比例、缓存命中与单请求成本

压测必须覆盖真实“坏形态”

  • 突发短请求:验证 RPM 和 Token Bucket 是否平滑削峰
  • 超长上下文、长流式输出:验证输入/输出 TPM 与并发槽是否准确
  • Agent 扇出、热点缓存击穿:验证调用放大和 Singleflight
  • 注入 429、慢响应、备用模型故障:验证队列是否清空、Retry Budget 与降级质量
最终边界:若稳态需求长期接近或超过配额,限流算法无法弥补容量缺口。需要申请更高额度、购买预置吞吐、接入真正独立的 Provider,或部署自有推理服务;同时继续削减低价值流量。

10. 生产落地清单

第一阶段:先止血

  • 统一 429 处理层,关闭重叠自动重试;加 Retry Budget、Full Jitter 和 Deadline。
  • 按 Provider + 模型 + 区域隔离熔断,避免局部限流扩大为全局不可用。
  • 增加请求、Token、并发、队列、429 维度的观测与告警。

第二阶段:建立控制面

  • Gateway 前置统一准入;使用 Redis/Lua 或额度租约实现多实例原子配额。
  • 实现输入 Token 计算、输出预占、真实 usage 对账和流式连接释放。
  • 引入有界优先级队列、Deadline、背压、异步任务和租户公平调度。

第三阶段:提升有效容量

  • 精确缓存、语义缓存、Singleflight、Prompt Cache、上下文压缩和输出上限。
  • 为 Agent 限制步骤、并发分支、总 Token;把离线任务批处理。
  • 按任务价值路由到大小模型、独立 Provider 与适当的异步路径。

第四阶段:持续校准

  • 用 response headers 和 usage 校准本地桶;以 P95/P99 而非平均值规划。
  • 用 AIMD 自适应调节出站速率和并发;定期演练 429、慢响应与备链路故障。
  • 需求长期超限时,走提额、预置吞吐或自建容量,而非继续堆重试。
面试 / 方案总结:我会先把上游的 RPM、输入/输出 TPM 和流式并发槽建模成容量池,在 LLM Gateway 做全局准入。请求先计算输入 Token、预留输出 Token,并原子获取多维预算;拿不到预算就按优先级进入有界队列、转异步、降级或快速失败。429 只在一个层级以 Retry-After + Jitter + Retry Budget 受控处理,并反向驱动自适应收缩。再用缓存、Singleflight、Token 优化、模型路由和 Brownout 降低需求,最终通过真实 usage、队列年龄、429 原因和 P99 延迟持续校准。