停止排队推理请求
Source: Dev.to
问题概述
大多数推理后端在突发负载下会退化。
这不仅限于大语言模型(LLM),任何受限的计算系统都会出现:
- 单个 GPU
- 本地模型运行器
- CPU 受限的工作者
- 紧凑规模的推理集群
当需求激增时,大多数系统会采取以下两种做法之一:
- 接受所有请求,让请求在内部累积。
- 在入口处限流。
这两种方式都掩盖了真正的问题。
- 队列不断增长。
- 延迟拉长。
- 重试加剧压力。
- 内存使用变得不可预测。
- 过载变得不透明。
你不会立刻看到失败,只会看到缓慢的衰退。
缺失的边界
限流 与 执行治理 是有区别的。
- 限流 控制请求到达的速度。
- 执行治理 控制允许运行的请求数量。
这两者并不相同。你可以限流,却仍然构建一个无限的内部队列。如果不对并发执行施加硬性上限,后端本身就会成为队列,而在突发负载下的队列是隐蔽的负债。
另一种思路:显式 Yield
与其缓冲过载,不如将其转化为显式响应。当容量已满时:
- 不排队。
- 不阻塞。
- 不悄悄延迟。
返回:
status = yield
retry_hint_ms =
系统保持有界,客户端自行决定何时重试,过载变得显式而非隐藏。
具体示例
下面是一个简单的测试:
max_inflight = 1- 20 个并发客户端
- 后端执行时间 = 10 秒
观察到的状态转变:
t=44 inflight=1 executed_total=1 yielded_total=19
t=79 inflight=0 executed_total=1 yielded_total=19
解释
- 同时进行的请求数从未超过 1。
- 只有一个请求被执行。
- 其余十九个请求立即被 yield。
- 队列没有增长。
系统没有退化,保持了有界性。
为什么这对推理系统重要
推理工作负载本身是突发的;提示词并不是平滑曲线到达,而是成簇出现:
- 用户刷新风暴
- 重试循环
- 并发 UI 事件
- 负载均衡器重新分配
- 自动伸缩延迟
如果你的后端悄悄缓冲这些突发,你将会在后期承受尾部延迟和内存压力。对执行进行有界限制并在超载时返回 yield,将隐式的不稳定性换成显式的回压——这几乎总是值得的权衡。
这不是
这 不是:
- 调度器
- 策略引擎
- 公平性系统
- 网关
- 仪表盘
- 分布式运行时
它是一个狭义原语:硬并发上限 + 显式 yield。仅此而已。
一个小工具,故意保持简约
我围绕这个思路实现了一个小型入口治理器。它:
- 接收以换行分隔的 JSON 帧(TCP)
- 验证上传完整性
- 强制
max_inflight - 当饱和时立即返回
yield - 暴露最小指标(
inflight、executed_total、yielded_total)
它 不 检查提示词、不对模型进行 introspection、也不计数 token 或应用策略。它仅仅治理执行槽——别无他物。
为什么不直接用 Nginx?
因为限流并不是执行治理。你可以限制每秒请求数,却仍然允许后端接受无限数量的并发提交。有限并发和显式 yield 是不同的原语;它们可以共存,但解决的问题不同。
核心思想
停止把过载当作需要缓冲的东西。把它当作需要暴露的东西。如果容量已满,就直接说明。返回 yield。保持有界。