静态
固定大小的批次,要等装满才发。适合离线任务,但不适合交互式流量,因为所有人都得等这一批。
决定一组 GPU 能服务多少请求、以多快速度服务的系统级技术:批处理、KV 缓存的显存管理、decode 加速、阶段分离、并行与路由。延迟、吞吐量和成本相互拉扯;究竟偏向哪一头,由工作负载决定。
单个请求会让 GPU 大部分算力闲置;把请求聚在一起,可以让每次权重读取被许多 token 分摊。怎么聚很关键:
固定大小的批次,要等装满才发。适合离线任务,但不适合交互式流量,因为所有人都得等这一批。
批次按时间窗口或大小上限关闭,等待时间因此有了上界。这更好,但一批仍然要等它最慢的成员跑完。
调度器以 token 为粒度工作:已完成的序列中途离开,排队的请求立刻加入。这是当前主流的默认方式(vLLM、SGLang、TensorRT-LLM),也是单项收益最大的利用率改进。
chunked prefill 进一步细化了它:长提示词被切成小块,与 decode 步骤交错执行,于是一个超长提示词不会再卡住其他所有人的 token 流。批处理策略就是延迟策略;请测量 TTFT 和 token 间延迟,而不只是每秒 token 数。
朴素的服务实现会按每个请求可能的最大长度预留连续的 KV 显存,其中大部分以碎片的形式被浪费。PagedAttention 借用了虚拟内存的思路:缓存存放在按需分配的定长块中,并用一张块表把每个序列的逻辑位置映射到物理块。浪费因此降到大约最后一个不满的块,相同前缀可以共享物理块,回收出的显存则转化为更大的有效批次。它由 vLLM 提出,如今已是各服务引擎的标准做法;这是显存管理上的胜利,而不是更快的内核。
如果两个请求以字节完全相同的 token 前缀开头(相同的系统提示词、相同的示例、相同的对话历史),这段前缀的 prefill 计算就可以只做一次并复用,每命中一次都能降低 TTFT 和 prefill 算力。它要求 token 精确匹配,这正是提示词纪律重要的原因:静态内容放前面,易变取值(时间戳、用户数据、请求 ID)尽量靠后,序列化保持确定性。请跟踪命中率;命中率低通常意味着提示词模板把变化泄漏到了开头。
缓存随上下文长度和并发线性增长,而 GPU 的 HBM 会最先耗尽。卸载会把较冷的缓存转存到 CPU 内存、本地 SSD 或远端存储,需要时再取回,于是空闲的会话和长期共享的上下文不再占着 HBM 不放(LMCache 是最常见的开源实现,已与 vLLM 集成)。它在长上下文和可恢复会话场景下值得采用;权衡在于传输时间与重新计算之间,因此请在你自己的存储层级上把两条路径都测一遍。
decode 受内存限制,因此每一步都有富余算力。一个廉价的草稿模型提出若干 token;目标模型用一次前向把它们一起校验,接受其中最长的正确片段。被接受的 token 只花了很小的代价;被拒绝的草稿则退回常规解码,而严格的校验方案能保持目标模型的输出分布不变。
prefill 受算力限制且呈突发状;decode 受带宽限制且相对平稳。二者混在一起会互相干扰:一次长 prefill 会卡住所有人的 token 流。分离部署把两个阶段放到各自的工作节点池上,独立扩缩容和调优,由 prefill 节点通过高速网络把 KV 缓存发送给 decode 节点。传输就是要付的税,所以它在机群规模下才划算,在小规模或短提示词场景下反而吃亏;支持的框架包括 vLLM、SGLang 和 NVIDIA Dynamo。
数据并行复制模型并分摊流量。张量并行把单层切分到多张 GPU 上,让过大的模型放得下,代价是每一步都要通信(它需要 NVLink 级别的互联)。流水线并行把层区间分配给各个阶段,并用微批次填补流水线气泡。专家并行把 MoE 的专家分散到不同设备上。真实部署会把这些组合起来,而最佳配比只能靠实测:张量并行会加大带宽压力,复制则会压缩每张 GPU 的 KV 余量,所以请对具体配置做基准测试,而不要凭第一性原理推演。
当副本很多时,路由器本身就成了一个优化面。轮询忽略了 LLM 场景里所有真正重要的因素;更好的信号是当前负载、显存余量,尤其是缓存局部性:前缀感知或会话粘滞的路由会把请求送到它的 KV 状态已经存在的地方(对提示词前缀做一致性哈希是常见做法,llm-d 等项目就在用)。分离部署的机群按阶段路由,优先级或 SLA 分级以及适配器的所在位置也可以纳入同一套打分。这与在不同档位模型之间做选择的路由是两回事,后者见智能体模式。
并非所有工作负载都是交互式的。语料嵌入、分类回填、批量摘要和评测运行都能容忍数小时的延迟,这会彻底改变优化目标:把硬件跑满,使用闲置或非高峰时段的算力(服务商正是为此提供打折的批量档位),并在结果被使用之前加上后处理和质量检查。把批量任务挡在交互式机群之外,同时也保护了你的延迟 SLO。