ARTICLE · 软件编程

并发控制:不要自毁速率限制

作者:Multigrid 来源:DEV Community: machinelearning 2026-08-08 06:57 6 分钟 6 阅读 1415 字
AI 工程并发控制速率限制系统设计令牌桶
一语总结

本文介绍了一套面向 AI 推理 API 的生产级并发控制系统,涵盖三个限制条件(并发数、请求速率、Token 速率)、用于容量规划的 Little's Law、带边界队列的信号量、采用悲观估算的令牌桶,以及自适应 AIMD 控制。

AI 总结

文章探讨了在调用 AI 推理 API 时如何保持在服务商速率限制之内的问题。这类 API 通常会同时施加三个限制:在途并发数(客户端侧)、每分钟请求数、每分钟 Token 数。文章解释了为什么只控制请求速率会失败——Token 限制可能被静默突破,而且返回的 429 错误与其他情况完全相同。作者利用 Little's Law,根据吞吐量和观测到的延迟推导出正确的并发目标,并指出固定限制本质上是对一个非恒定时长的下注。文中提供了一个生产可用的 Semaphore 实现,其中包含两个关键细节:使用有界队列防止服务商变慢时发生 OOM,以及在释放时检查过期状态以免执行已过期的请求。对于 Token 限制,推荐使用令牌桶,按估算的输入 Token 和 max_tokens 扣减,并在实际用量出来后退款,且更倾向于悲观估算。自适应并发采用加法增加/乘法减少(AIMD),根据成功、429、超时来调整,并按区间评估以避免震荡,同时设有上下限。最后,文章讨论了分布式限流器的部署位置:静态分片、基于 Redis 的租约,或单一代理,并强调限流范围必须与服务商的范围(按 Key、模型或组织)匹配。

核心要点
  1. AI 推理 API 会施加三类不同的限制:并发数、每分钟请求数、每分钟 Token 数。

    只控制请求速率会忽略 Token 限制;大提示词或高输出 Token 都可能突破该限制,而且返回的 429 错误与其他情况无法区分。三类限制需要各自的独立机制。

  2. Little's Law 给出了正确的并发目标:目标吞吐量 × 平均调用时长。

    由于推理时长会随提示词长度、输出长度、模型和提供方负载而变化,固定并发限制本质上是对一个非常量值下注。该定律也可以反向使用,通过延迟回归来发现容量损失。

  3. 生产级信号量需要有限队列,并在释放时检查过期状态。

    无界队列会把提供方变慢转化成为 OOM 崩溃。过期检查可以防止系统恢复后执行那些调用方早已超时的请求,从而避免把容量浪费在无效工作上。

  4. 针对 Token 限制的令牌桶应进行悲观扣减(按 max_tokens),并在实际用量后退款。

    输出 Token 事先无法预知;过度扣减只会损失少量吞吐,而扣减不足则会导致 429,触发重试并进一步消耗本要保护的配额。收到 429 时,应遵循 Retry-After 并暂停整个桶。

  5. 通过 AIMD(加法增加、乘法减少)实现的自适应并发优于固定限制。

    在 429 或超时时进行乘法减少至关重要,因为设置得过高(在不稳定的依赖上触发重试)的成本远高于设置得过低。上下限和基于区间的评估可以防止震荡。

并发控制:不要自毁速率限制

文章探讨了在调用 AI 推理 API 时如何保持在服务商速率限制之内的问题。这类 API 通常会同时施加三个限制:在途并发数(客户端侧)、每分钟请求数、每分钟 Token 数。文章解释了为什么只控制请求速率会失败——Token 限制可能被静默突破,而且返回的 429 错误与其他情况完全相同。作者利用 Little's Law,根据吞吐量和观测到的延迟推导出正确的并发目标,并指出固定限制本质上是对一个非恒定时长的下注。文中提供了一个生产可用的 Semaphore 实现,其中包含两个关键细节:使用有界队列防止服务商变慢时发生 OOM,以及在释放时检查过期状态以免执行已过期的请求。对于 Token 限制,推荐使用令牌桶,按估算的输入 Token 和 max_tokens 扣减,并在实际用量出来后退款,且更倾向于悲观估算。自适应并发采用加法增加/乘法减少(AIMD),根据成功、429、超时来调整,并按区间评估以避免震荡,同时设有上下限。最后,文章讨论了分布式限流器的部署位置:静态分片、基于 Redis 的租约,或单一代理,并强调限流范围必须与服务商的范围(按 Key、模型或组织)匹配。

文章金句

"

固定并发限制本质上是对一个并不恒定的常量下注。

"

如果没有边界,提供方变慢就会变成无界的内存增长。如果没有过期检查,恢复中的系统会把最初的几分钟浪费在执行那些调用方早已离开的请求上。

"

过度扣减只会让你损失一点吞吐量;扣减不足则会带来 429,而 429 又会带来重试,重试会进一步消耗你本要保护的配额。

"

设置过高的代价远高于设置过低:过高意味着 429,429 意味着重试,重试意味着给本已不稳定的系统增加更多负载。