优化大语言模型性能:解决长提示阻塞和解码慢速问题
TL;DR
在 LLM 服务中,长提示会阻塞预填充队列并减慢并发请求的 token 生成。为了解决此问题,请求并行预填充可以降低短提示的首 token 时间(time-to-first-token),而分离预填充则将预填充和解码阶段放在不同的 GPU 上,从而消除干扰并稳定延迟。
长提示阻塞的挑战
在标准的 LLM 服务中,预填充阶段(处理初始提示)计算密集,可能会使 GPU 利用率饱和,而解码阶段(生成后续 token)计算需求较低。在 vLLM 使用的默认分块预填充策略中,不同请求的预填充块是顺序调度的。
当调度一个提示非常长的请求时,它会阻塞预填充队列。随后到来的请求必须等待该长预填充完成后才能开始各自的预填充阶段,从而显著增加这些请求的首 token 时间(TTFT)。
请求并行预填充
为了解决队列阻塞,vLLM 实现了一种策略,允许对多个请求进行并行预填充,但对同时处理的长提示数量有限制(例如,允许四个并行预填充,但仅有一个超过 10,000 token)。
- 对短提示的影响: 短提示现在可以通过“快车道”绕过长预填充,显著降低其 TTFT。
- 对长提示的影响: 长提示仍然按顺序处理,以避免如果将多个计算密集的预填充批量执行时导致的系统严重慢速。
- 限制: 虽然 TTFT 已降低,但每个输出 token 的时间仍然偏高,因为并发的预填充仍占用 GPU 资源,导致已有请求的解码步骤变慢。
基本缺陷:预填充-解码干扰
在同一 GPU 操作中为不同请求执行预填充和解码会导致 token 生成速度下降。单个长提示请求就足以削弱所有已调度且当前处于解码阶段的请求的性能。
缓解策略
- 优先级惩罚: 可以强制长提示等待高优先级或短请求完成。这会增加长提示的延迟,并且在长提示实际被调度后仍未解决干扰问题。
- 专用推理服务器: 将长提示请求路由到独立的服务器。这需要复杂的路由器和额外的 GPU 资源,尽管短上下文服务器可以在更少的 GPU 上部署(例如,Llama-3.3-70B 在 130k 上下文需要四块 H100,而在 <10k 上下文只需两块 H100)。
- 分离预填充: 为预填充和解码使用独立的推理引擎。该架构涉及多个 vLLM 部署,其中一个工作节点仅负责预填充,另一个仅负责解码。预填充完成后,KV 缓存会转移到解码工作节点。
分离预填充用于延迟优化
分离预填充消除了并发预填充对解码阶段的直接干扰,是稳定 token 生成延迟的最有效策略。
权衡与当前状态
- 资源成本: 该方法需要为每个角色部署独立的完整 vLLM(例如,Llama-3.3-70B 需要八块 H100:四块用于预填充,四块用于解码)。
- GPU 利用率: 由于预填充比解码更计算密集,利用率常常不均衡。不过,大规模集群可以通过根据负载模式调整预填充与解码工作节点的比例来平衡。
- 目标: 主要目标是提升“有效吞吐”(满足延迟目标的请求率),而非总的原始吞吐量。
- 实验状态: 截至 vLLM v0.7.3,该功能仍属实验性。当前的限制包括较低的上下文长度上限以及解码工作节点对 CUDA 图的不一致使用,这可能导致解码速度比集成部署更慢。