跳到主要内容

混合 LLM 工作负载的 GPU 调度:那个没人解决好的装箱问题

· 阅读需 11 分钟
Tian Pan
Software Engineer

大多数运行 LLM 推理的 GPU 集群正在浪费 30% 到 50% 的可用算力。这并非因为工程师粗心,而是因为调度问题本身极为困难——而大多数团队首先想到的工具根本不是为此设计的。

标准做法是搭建 Kubernetes,为每个 Pod 申请完整的 GPU,然后让调度器自行处理。这对训练任务运行良好。但对于处理异构模型集合的推理场景,这种方式会悄悄摧毁利用率。一个运行三个不同 7B 模型且流量稀疏的集群,每个 GPU 的实际繁忙时间可能不足 15%,同时却处于完全"已分配"状态,拒绝调度任何新任务。

根本原因在于 Kubernetes 理解 GPU 的方式与 LLM 推理实际需求之间的错配。

Kubernetes 为何在这里失效

Kubernetes 将 GPU 视为原子单元。一个申请 nvidia.com/gpu: 1 的 Pod 会获得一整块物理 GPU——A100 上 40GB 的 HBM,H100 上 80GB——无论工作负载实际需要多少。这在工作负载是训练任务或批量推理作业、确实需要占用整个设备时是合理的设计决策。但在混合服务场景下,这种设计彻底失效。

具体失效方式如下:

无法感知 KV 缓存。 Kubernetes 调度器对运行中 Pod 的 KV 缓存占用率毫无感知。在 LLM 推理中,KV 缓存占用率是运行时最重要的资源约束——它决定实例能处理多少并发请求,以及新请求是进入队列还是直接失败。将一个长上下文请求路由到缓存利用率 90% 的 Pod,与路由到 10% 利用率的 Pod,会产生截然不同的延迟。调度器根本看不到这种区别。

模型加载延迟不可见。 启动一个新的推理 Pod 并非即时完成。仅容器镜像拉取就可能需要 2–5 分钟,因为镜像包含数 GB 的模型权重。之后还有 CPU 上的权重反序列化、传输到 GPU 内存,以及预热前向传播。生产环境中的冷启动总时间通常为 2–5 分钟。Kubernetes 会毫不犹豫地将 Pod 调度到一个让用户等待四分钟才能得到响应的节点上,因为它没有模型加载状态的概念。

批次合并不可能实现。 水平 Pod 自动扩缩(HPA)依据 CPU 和内存指标触发。而在 LLM 推理最需要扩容的时刻——队列深度积压、请求等待 token 生成——内存利用率可能只有 30%(空闲推理服务器的正常水平),CPU 利用率也很平稳。系统看起来一切正常,而用户却在经历无限制的队列延迟。

结果是:团队大量过度配置,为每个服务的模型保持热实例,用持续的 GPU 闲置成本来规避冷启动惩罚。这不是配置问题,而是 Kubernetes 所暴露的能力与 LLM 调度所需能力之间的根本性鸿沟。

内存碎片化问题

即使在请求到来之前,混合模型集群就已经因碎片化损失了大量容量。

一个服务 8B 模型的 vLLM 实例可能预分配 60GB GPU 内存,而在典型负载下只使用 35–40GB。这在传统意义上并非浪费——考虑到潜在的最坏情况上下文长度,这种分配是正确的——但这意味着其他模型无法共享该设备,即便它处于低利用率状态。

单看 KV 缓存需求,数字更加触目惊心。一个 100,000 token 上下文的 7B 模型大约需要 50GB 用于 KV 缓存,而模型权重本身只需 14GB。四分之三的内存消耗是瞬态上下文状态,而非模型本身。传统静态分配将这部分视为永久占用,阻断了其他用途对该容量的使用。

在 PagedAttention(vLLM 的核心创新)出现之前,系统通过碎片化浪费了 60–80% 的已分配 KV 缓存内存:不连续分配、最坏情况预分配、请求间的内部碎片。PagedAttention 将操作系统用于虚拟内存的分页技术应用于此,将 KV 缓存浪费降至 4% 以下。这在同等硬件上实现了 2–4 倍的吞吐量提升——不是通过增加 GPU,而是更好地利用现有 GPU。

量化提供了另一个杠杆。将 KV 缓存从 FP16 迁移到 FP8 可在质量影响极小的情况下将缓存大小减半;NVFP4 进一步压缩,在同等设备上支持更大的批次或更长的上下文。但量化本身并不能解决调度问题——它只是改变了调度器需要追踪的数字。

真正能回收闲置容量的方法

以下三种策略切实有效,按实现复杂度大致递增排序。

时间切片与 MIG:分区 GPU

当需要在单块大型 GPU 上运行多个小模型时,分区是最直接的方法。

时间切片(所有 NVIDIA 架构均支持)在工作负载之间使用轮询上下文切换,每个任务占用 1–2ms 后让出。它启用简单,普遍适用,但上下文切换开销是真实存在的,在持续负载下会累积。更适合突发性、对延迟容忍度高的工作负载,而非持续推理。

多实例 GPU(MIG)(仅 Ampere 及更新架构)在硬件层面对物理 GPU 进行分区,为每个实例提供隔离的计算核心、专用内存和独立的 L2 缓存。无上下文切换开销,保证资源隔离。代价是灵活性不足:MIG 分区大小在配置时固定,分区大小与工作负载大小的任何错配都会浪费容量。

混合方式——MIG 分区加上每个分区内的时间切片——结合了两者的优势。一项基准测试显示,通用工作负载吞吐量提升 6.2 倍、能耗节省近 6 倍;LLM 特定工作负载显示出更适中的 1.4 倍吞吐量提升。这个范围反映了这些数字对工作负载特性的高度敏感性。

MIG 和时间切片都不涉及决定哪个请求去哪个 Pod 的调度决策。它们是资源配置策略,而非路由智能。

连续批处理:消除队头阻塞

静态批处理——等待固定数量的请求后再开始批次——是从传统 ML 推理继承的默认行为。它会产生队头阻塞:一个提示词很长的早期请求会阻塞整个批次直到完成,无论后续请求的大小如何。

连续批处理通过迭代级调度消除了这个问题。每当一个序列完成一个解码步骤,批次就可以从队列中吸收一个新请求。不会有请求等待另一个请求完成全部生成。GPU 保持忙碌,短请求不会在长请求后面排队,吞吐量随负载扩展,而不受批次配置限制。

对于生产 LLM 服务,这不是可选项,而是基本门槛。vLLM 早期就实现了它。在同等硬件上,静态批处理与连续批处理在中等并发度下的差距是 2–4 倍吞吐量。

KV 缓存感知路由:新前沿

影响最大——也最少被部署——的优化是将请求路由到已在 KV 缓存中持有相关上下文的 Pod。

收益相当显著。如果某个 Pod 已缓存了用户对话的前 4,000 个 token,将该对话的下一个请求路由到同一 Pod,相比路由到冷 Pod,首 token 时间可减少高达 74%。在企业规模下——150 个客户共享 6,000 token 的上下文前缀,总 KV 缓存需求占集群容量 73%——智能路由可以决定系统是否能够正常运行。

Kubernetes Gateway API 推理扩展(2026 年初 GA)添加了实现这一目标所需的原语:模型感知路由、基于队列深度和 KV 缓存利用率的 HPA 自定义指标,以及按模型进行流量分割。基于此,llm-d 提供了一个 Kubernetes 原生推理调度器,根据 KV 缓存状态、预填充/解码阶段、SLA 约束和当前负载对 Pod 进行过滤和评分。当请求到达时,它能识别哪个 Pod 持有最相关的缓存上下文并路由过去——将集群分散的 KV 缓存转变为一个连贯的资源,而非孤立的孤岛。

代价是运维复杂性。KV 缓存感知路由要求网关知道哪些 Pod 缓存了哪些前缀。这些状态必须被维护、同步,并在缓存驱逐旧块时失效。这是一个非平凡的分布式系统问题。

冷启动陷阱

以上所有内容适用于稳态服务。冷启动问题在不同时间尺度上运作,并破坏动态扩缩策略。

生产环境中典型冷启动的分解:

  • VM 或节点配置:30–60 秒
  • 容器初始化:5–10 秒
  • 镜像拉取:1–5 分钟(10–30GB 镜像)
  • 运行时启动和权重获取:30–60 秒
  • CPU 反序列化:30–120 秒
  • GPU 内存分配和权重传输:15–80 秒
  • 预热前向传播:5–30 秒

总计:从零到首 token 通常超过 5 分钟。

缩容至零以节省成本的系统,在任何流量峰值期间都会违反 SLO。为避免冷启动而保持实例热备的系统,则持续为闲置 GPU 付费。业界正在向预测性自动扩缩汇聚作为答案:通过从历史模式和前导指标预测负载,在需求到来之前启动实例。DynamoLLM(HPCA 2025)展示了这种方法,预测下一个调度周期的峰值负载并主动配置实例。在此基础上,延迟镜像拉取(stargz Snapshotter)和直接到 GPU 的权重流式传输可以将冷启动时间再缩短 60–80%。

选择服务框架

你的调度策略与推理框架的选择直接交互。

vLLM 是当前高吞吐量场景的标准。PagedAttention、连续批处理和前缀缓存均为原生支持。在规模化场景下吞吐量最高。

SGLang 对于具有共享提示前缀的工作负载——对话 AI、智能体工作流、任何多个请求共享长公共前缀的场景——比 vLLM 性能高出 10–20%。其 RadixAttention(前缀缓存的等效实现)在复用上更为激进。

TGI 于 2025 年 12 月进入维护模式。Hugging Face 建议新部署使用 vLLM 或 SGLang。如果你在生产中运行 TGI,请规划迁移。

Triton / NVIDIA Dynamo 针对同时服务来自不同框架模型的多框架集群。并非针对 LLM 优化,但对于多模态或混合框架服务是正确选择。

Ray Serve 是通用 Python 服务框架——灵活性有用,但若不针对 LLM 特定关切进行手动优化,则性能欠佳。

真正重要的是什么

按影响力排序的实践优先级:

  1. 切换到连续批处理。 如果你仍在使用静态批处理,这是你影响力最高的改变。同等硬件上 2–4 倍吞吐量,无需调度变更。

  2. 采用 PagedAttention。 vLLM 的内存管理将 KV 缓存浪费从 60–80% 降至 4% 以下。这解锁了碎片化隐藏的容量。

  3. 启用前缀缓存。 对于具有重复系统提示或共享上下文的工作负载,自动前缀缓存可在缓存命中时将首 token 时间减少 74%。这在 vLLM 中只是一个配置开关,打开即可。

  4. 用分区替代 Kubernetes GPU 原子性。 对于不需要完整 GPU 的模型使用 MIG 或时间切片。操作上简单直接,根据工作负载组合回收 1.4–6 倍容量。

  5. 添加 KV 缓存感知路由。 复杂度更高,回报也更高。如果你是 Kubernetes 原生,从 Gateway API 推理扩展开始;llm-d 在此之上添加调度智能。

  6. 通过预测性扩缩解决冷启动问题。 一旦以上措施到位,冷启动延迟就成为流量峰值下的主要故障模式。延迟拉取和预测性自动扩缩可以弥合这一差距。

构建可扩展 LLM 服务基础设施的团队,并不是通过增加 GPU 来实现的。他们的做法是让现有 GPU 停止在被标记为已分配的情况下依然空闲。

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