跳到主要内容

LLM 流水线的背压模式:为何指数退避还不够

· 阅读需 11 分钟
Tian Pan
Software Engineer

在峰值流量期间,部分 LLM 提供商的失败率超过 20%。当系统撞上这堵墙,并通过加倍等待时间和重试来应对时,你解决的是一个错误的问题。指数退避处理的是单次调用的韧性,对整个系统毫无作用——无法减少浪费的 token,无法解决连接池耗尽,也无法照顾到排在刚收到 429 响应那个请求后面的 50 个请求。

冲击 LLM API 的流量模式也发生了根本性变化。2023 年到 2025 年间,100 token 以下的简单查询从占流量的 80% 骤降至约 20%,而超过 500 token 的请求则成为持续的多数。Agentic 工作流在短时间内串联 10-20 个顺序调用,产生的流量模式在传统的每分钟请求数(RPM)限速下,与 DDoS 攻击别无二致。为负载可预测的 REST API 构建的基础设施,并不是 LLM 流水线所需要的基础设施。

本文介绍真正有效的生产模式:令牌桶队列、优先级通道路由、具备令牌预算感知的熔断器,以及主动负载卸除。每一层都解决上一层无法应对的故障模式。

为何指数退避在系统层面失效

指数退避是被动的、无状态的。它仅在收到 429 后触发,将等待时间加倍(base × 2^n,上限约 60 秒),加入抖动以防止多个客户端同步重试,然后再次尝试。在孤立测试中,这运行良好。在生产环境中,多个调用方共享同一限速配额时,就会产生"惊群"问题。

实际发生的情况是:流量峰值触发了整个工作池的 429。所有 Worker 退避。限速窗口重置。所有 Worker——因为几乎同时收到了 429——同时恢复。由此产生的请求突发再现了原来的过载。你把一个流量峰值变成了持续的振荡。

更深层的问题是,指数退避在错误的抽象层面上运作。它衡量请求数,但提供商按 token 限速。一个 50 token 的提示和一个 10,000 token 的提示在 RPM 限制下各算一个请求,但资源消耗差异悬殊。一个将二者等同对待的系统,会在触及每分钟请求数限制之前先触及每分钟 token 数限制,而任何退避调优都无法修复这一根本性的错配。

令牌桶队列:让你的速率与提供商的现实相匹配

令牌桶算法维护一个虚拟的容量余额。令牌以固定速率补充,直至上限。每个出站请求消耗与其预估 token 数成比例的令牌。当桶空时,请求等待,而不是直接发送并失败。

关键洞察在于在提供商之前本地运行此逻辑——而不是在收到 429 后被动响应。典型配置如下:

  • 最大桶容量:10,000 个令牌(吸收合理的突发流量)
  • 补充速率:每秒 1,000 个令牌(匹配你的提供商 TPM 档位)
  • 消耗量:入队时的预估提示 token 数 + max_tokens

这正是提供商自身执行限制的方式——使用连续补充至上限,而非在固定时间间隔硬性重置。在本地运行同步的桶,意味着你的系统与提供商的窗口保持一致。你还需要解析每个响应的限速响应头(x-ratelimit-remaining-tokensx-ratelimit-reset-tokensretry-after),以保持本地桶与提供商实际状态同步,而不是依赖估算。

令牌桶与漏桶的一个重要区别在于:令牌桶允许合理的突发并随后执行稳态速率,而漏桶将所有流量平滑为恒定的输出速率。对于本质上是突发性的交互式 LLM 流量,令牌桶通常是正确的默认选择;对于优先级是不给提供商造成过大压力的后台批量推理,漏桶才是正确的选择。

优先级通道:并非所有请求都生而平等

一旦有了队列,就必须决定请求的出队顺序。默认是 FIFO,而 FIFO 对混合工作负载的 LLM 系统是一场灾难。

一个直观的三级模型能覆盖大多数生产场景:

  • 交互式(P0): 用户侧聊天、实时补全。要求 5 秒内响应。延迟直接导致用户流失。
  • 非交互式 API(P1): 自动化代码审查、Webhook 触发的摘要。可以容忍几秒到几分钟的延迟。
  • 批量/计划任务(P2+): 文档索引、评估运行、批量分类。可以在数小时内或隔夜完成。

没有明确的优先级通道,P2 批量作业的突发会堵塞队列,阻断所有 P0 交互式请求。IBM Research 的队列管理研究表明,与 FCFS 基线相比,专用优先级调度将 SLO 达成率提升了 40-90%,吞吐量提升了 20-400%。这个范围很宽,因为收益随着工作负载差异的大小而扩大——但凡混合了交互式和批量流量的团队都能持续受益。

对于自托管推理服务(vLLM 等),优先级调度现在包含了抢占机制:当 P0 交互请求到来时,调度器暂停 P2 批量请求、保留其 KV 缓存,并在容量可用时恢复它。这在不完全丢弃在途工作的前提下,避免了对交互用户的延迟影响。

生产优先级通道的两个实操要点:

第一,衡量 P99 延迟,而非平均响应时间。如果 1% 的用户遇到 30 秒的延迟,无论平均延迟如何,系统都是不可靠的。优先级通道的目标是为 P0 流量保证 P99 SLO,而不是最大化平均吞吐量。

第二,使用截止时间传播。客户端应通过响应头或 gRPC deadline 将截止时间提示传递给上游,以便服务器在推理开始前拒绝已超时的请求。一个在队列中等待 60 秒以上的请求,几乎可以肯定已经超过了客户端超时时限,再开始推理只是烧 token 并产生永远无法送达用户的输出。

具备令牌预算感知的熔断器

熔断器是一种标准的韧性模式:在连续失败达到阈值后,停止向故障端点发送请求(OPEN 状态),等待冷却期,然后用单个请求探测(HALF-OPEN),仅在探测成功时重新闭合。其性能差异是可量化的——在模拟停机期间,熔断器将用户可见错误减少了 90% 以上,并消除了数千次对无响应端点的无效 API 调用。

LLM 特有的问题是,标准触发条件——HTTP 错误率、连续 429 次数——会错过三种在错误率攀升之前就已造成损害的故障模式:

缓慢退化。 在任何 429 出现之前,提供商响应时间从 2 秒增加到 25 秒。错误率保持低位;延迟攀升,token 成本飙升。只监视错误率的熔断器在系统退化时保持闭合。

部分上下文失败。 在正式限速之前,提供商有时会对大上下文请求返回格式错误或截断的补全内容,而 HTTP 状态码仍是 200。标准熔断器看不到这个问题。

成本失控。 Agentic 循环持续成功(200 OK),同时以不可持续的速率消耗令牌预算。GetOnStack 事件——一个未被检测到的 Agent 间无限循环,运行了 11 天,将费用从每周 127 美元飙升至 47,000 美元——是熔断器监视了错误指标的典型案例。

生产级 LLM 熔断器至少应监控四个信号:

  • Token 消耗速率 相对于提供商 TPM 限制——在 85% 时触发,留出余量
  • P95 延迟——若 P95 超过基线的 3 倍,在错误积累前开路
  • 每小时成本——以美元计的上限,用于捕获失控的 Agent
  • 连续 429 次数——传统触发条件,仍然必要

当熔断器处于 OPEN 状态,在 HALF-OPEN 状态发送探测时,使用轻量级金丝雀:在快速模型上发送一个简单的"回复 OK"调用,设置 max_tokens=5,超时 5 秒。永远不要用真实的生产提示作为探测——它会消耗 token,有数据泄露风险,并且在提供商仍处于降级状态时需要更长时间才能失败。

将回退链设计为在你自己掌控的资源上终止:

主提供商 → 备用提供商 → 本地模型(始终可用)

第三层至关重要。如果你的回退链以另一个受速率限制的云端点结束,你并没有真正终结依赖——只是转移了它。

主动负载卸除:在失败之前拒绝

前述模式是流量控制机制——它们调节请求进出系统的速度。负载卸除则不同:它是决定根本不服务某些请求,而不是无限期地将它们排队。

分布式系统的核心洞察是,在过载情况下,接受所有请求然后让大多数失败,严格劣于接受较少请求并完成所有请求。前者浪费算力、消耗 token、耗尽连接池,并延长队列中所有请求的延迟;后者为你确实接受的请求维持了可靠的服务。

基于队列深度的卸除是最简单的实现:设置最大待处理队列深度(以及相应的最大等待时间)。一旦任一阈值被超过,新到的请求立即收到 503,而不是获得队列槽位。这种拒绝在 API 网关层成本最低——请求永远不会到达推理 Worker,不消耗 token,客户端得到一个快速明确的信号,可以稍后重试,而不是在过载队列中苦等。

对于 Agentic 流水线,将卸除扩展到单个会话内的累计令牌预算。当流水线在单个任务或对话中超过令牌预算阈值时,强制停止。Shopify 测量发现,工具调用的输出消耗的 token 约是用户消息的 100 倍——一个处于工具调用循环中的 Agent 可以在数小时内耗尽月度预算。会话级令牌预算上限是结构性保障,而监视请求数的熔断器无法捕获这一点。

一个实践细节:在高负载下,优先卸除最新到达的请求,而非最早的请求。等待时间最长的请求很可能已经超过了客户端的超时预算。在卸除新请求的同时保留它们在队列中,浪费了处理能力,产生的输出即使被处理也无法送达用户。

综合运用

这四层各自解决不同的故障模式,相互补充而非相互替代:

  • 令牌桶队列 通过将出站流量的节奏与提供商容量相匹配,从一开始就防止 429 的发生
  • 优先级通道 确保在容量受限时,容量流向最有价值的工作
  • 熔断器 快速检测提供商降级,并在故障通过系统传播前重新路由流量
  • 负载卸除 作为最后一道防线,将队列溢出转化为快速、明确的拒绝,而非缓慢的级联失败

将它们串联起来的模式是异步解耦:

API 网关 → 消息队列 → 工作池(令牌桶)→ LLM 提供商

Worker 以令牌桶控制的速率从队列中拉取。队列按优先级排序。熔断器位于工作池和提供商之间。网关执行队列深度限制,在请求进入队列前卸除多余负载。每一层都可以独立失败,而不会拖垮其他层。

这种架构的运维成本是真实的——它比简单的重试循环更复杂。但它是能在 LLM 应用实际产生的流量模式下保持稳定的架构:突发的交互式流量、后台批量作业、令牌消耗不可预测的 Agentic 工作流,以及偶尔在彻底失败前先行降级的提供商。指数退避处理的是简单情况,生产场景需要完整的技术栈。

References:Let's stay in touch and Follow me for more thoughts and updates