
1. 从一篇论文说起LLM Serving 的真实世界远比 benchmark 复杂如果你正在做 LLM 推理服务的部署和优化大概率经历过这样的场景实验室里用 vLLM 跑 Llama 3 8B吞吐量数据漂亮得不行结果一上生产环境P99 延迟直接爆炸GPU 利用率忽高忽低用户投诉不断。这不是你的问题而是大多数 LLM Serving 框架的 benchmark 环境和真实负载之间存在巨大的鸿沟。这篇论文的核心价值就在于此——它没有停留在“哪个框架更快”的层面而是系统性地拆解了 LLM Serving 在真实生产环境中的框架选型、方法取舍和系统设计逻辑。我前后读了三遍结合自己过去一年多在推理服务上的踩坑经历把论文里最值得关注的部分和实际落地经验揉在一起整理成这篇学习笔记。论文覆盖的范围很广从主流框架vLLM、TensorRT-LLM、TGI、SGLang 等的架构对比到连续批处理continuous batching、PagedAttention、Chunked Prefill 等关键方法的实际表现再到多副本调度、KV Cache 管理、异构硬件适配等系统设计问题。适合正在做 LLM 推理服务架构选型的工程师、需要优化线上服务性能的运维同学以及对推理系统底层机制感兴趣的研究者。不管你是刚接触 LLM Serving 的新手还是已经在生产环境里摸爬滚打了一段时间的老手这篇内容应该都能帮你理清一些之前模糊的认知。2. 论文到底研究了什么核心问题与实验设计拆解2.1 论文试图回答的三个核心问题这篇论文的出发点非常明确现有的 LLM Serving 研究大多在受控环境下做 benchmark但真实世界的负载特征、硬件配置、业务约束千差万别导致论文里的结论直接搬到生产环境经常不成立。所以作者提出了三个核心研究问题第一个问题是框架层面的不同 LLM Serving 框架在真实负载下的表现差异到底有多大这个问题的关键在于“真实负载”四个字。论文收集了多个生产环境的请求 trace包括请求到达模式、输入输出长度分布、并发特征等而不是用合成数据跑 benchmark。第二个问题是方法层面的连续批处理、PagedAttention、Chunked Prefill、投机解码这些优化方法在实际场景中各自的收益边界在哪里什么情况下该用、什么情况下不该用论文通过控制变量实验给出了每种方法的适用条件和性能拐点。第三个问题是系统设计层面的当单副本无法满足需求时多副本调度、KV Cache 跨副本管理、异构硬件混部等系统设计决策如何影响端到端性能这部分是论文最有价值的地方因为它触及了很多框架文档里不会写的工程细节。2.2 实验设计的几个关键选择论文在实验设计上有几个值得注意的选择这些选择直接影响了结论的可信度和适用范围。首先是负载的真实性。作者没有用单一的请求长度分布而是采集了多种业务场景的 trace包括对话类短输入短输出、摘要类长输入短输出、代码生成类短输入长输出、RAG 类长输入长输出。这四种场景对 Serving 系统的压力完全不同——对话类看重首 token 延迟摘要类看重 prefill 吞吐代码生成类看重 decode 吞吐RAG 类则对 KV Cache 容量极其敏感。其次是硬件配置的多样性。论文没有只在 A100 上跑实验而是覆盖了从消费级显卡到数据中心级 GPU 的多种配置包括不同显存容量、不同互联带宽的场景。这一点非常重要因为很多优化方法在高端卡上收益明显但在中低端卡上可能因为显存带宽瓶颈而完全失效。第三是指标的多维度。论文没有只看吞吐量或平均延迟而是同时报告了 TTFTTime to First Token、TPOTTime per Output Token、P99 延迟、GPU 利用率、显存占用等多个指标。这种多维度的评估方式才能揭示不同框架和方法之间的真实 trade-off。这里有个容易被忽略的点论文在报告吞吐量时区分了“系统吞吐”和“有效吞吐”。系统吞吐是所有请求的总 token 处理量而有效吞吐只计算在 SLO 约束内完成的请求。很多框架在宽松 SLO 下吞吐量很高但一旦收紧 SLO有效吞吐可能直接腰斩。2.3 论文结论的适用边界读这篇论文时我一直在提醒自己注意结论的适用边界。论文的实验环境虽然比大多数研究更贴近真实但仍然有一些限制。比如论文主要关注的是在线推理服务场景没有深入讨论离线批量推理的场景。离线场景下吞吐量是唯一目标延迟约束很宽松这时候很多在线场景下的最优选择可能完全不适用。再比如论文的实验主要集中在文本生成任务上对多模态模型、MoE 架构的覆盖有限。虽然部分结论可以迁移但 MoE 模型的 expert 路由和负载均衡问题会带来额外的复杂性。另外论文的硬件配置虽然多样但主要集中在 NVIDIA GPU 生态内对 AMD、Intel 等异构硬件的覆盖较少。如果你正在做国产芯片适配论文的很多结论需要重新验证。3. 主流框架的真实表现vLLM、TensorRT-LLM、TGI、SGLang 对比3.1 框架架构差异与设计哲学论文对主流框架的对比没有停留在功能列表上而是深入到了架构设计哲学层面。这一点让我重新理解了为什么有些框架在某些场景下表现差异巨大。vLLM 的核心设计哲学是“通用性和易用性优先”。它的 PagedAttention 实现是框架无关的可以适配多种模型架构部署门槛低社区生态活跃。但代价是在某些特定硬件和模型上性能不如专门优化的方案。论文的实验显示vLLM 在大多数通用场景下表现均衡但在极端长序列或超高并发场景下调度开销会成为瓶颈。TensorRT-LLM 走的是“极致性能”路线。它通过算子融合、kernel 自动调优、量化感知优化等手段在 NVIDIA GPU 上能压榨出最高的硬件性能。但论文也指出TensorRT-LLM 的编译流程复杂模型适配成本高而且对硬件型号有较强依赖。一旦换卡或者换模型架构之前的优化可能全部失效。TGIText Generation Inference的设计更偏向“生产就绪”。它在请求调度、健康检查、动态批处理等方面做了很多工程化的工作适合直接部署到生产环境。但论文的实验表明TGI 在极端负载下的弹性不如 vLLM当请求模式突变时TGI 的批处理策略调整不够及时。SGLang 则是“结构化生成”场景的专家。它的 RadixAttention 对多轮对话、树状推理等场景有天然优势KV Cache 复用效率极高。但论文也指出SGLang 在通用场景下的表现并不突出它的优势高度依赖于请求之间的前缀共享程度。框架核心优势主要短板最适合的场景vLLM通用性强、部署简单、社区活跃极端场景调度开销大通用在线推理、快速原型验证TensorRT-LLM单卡性能极致、量化支持好编译复杂、硬件依赖强固定硬件固定模型的规模化部署TGI生产工程化完善、稳定性好弹性调度不够灵活对稳定性要求高的生产服务SGLang前缀复用效率高、结构化生成强通用场景优势不明显多轮对话、树状推理、Agent 场景3.2 吞吐量与延迟的实测对比论文在吞吐量和延迟上的对比数据很有参考价值但更重要的是它解释了数据背后的原因。在短输入短输出场景对话类下vLLM 和 TensorRT-LLM 的吞吐量差距不大TensorRT-LLM 略优。但 TTFT 方面vLLM 反而更稳定因为它的调度器对突发请求的响应更快。TGI 在这个场景下表现中规中矩但 P99 延迟的波动最小说明它的调度策略更保守、更稳定。在长输入短输出场景摘要类下TensorRT-LLM 的 prefill 吞吐优势明显比 vLLM 高出约 20%-30%。这是因为 TensorRT-LLM 对 attention kernel 做了深度优化而 vLLM 的 PagedAttention 在长序列 prefill 时会有额外的内存管理开销。但论文也指出如果开启 Chunked PrefillvLLM 的差距会缩小到 10% 以内。在短输入长输出场景代码生成类下decode 阶段的性能成为关键。这个场景下SGLang 的表现出乎意料地好因为代码生成任务中不同请求之间的前缀共享程度很高比如同一个项目的多个补全请求RadixAttention 的 KV Cache 复用大幅减少了重复计算。在长输入长输出场景RAG 类下显存容量成为瓶颈。论文的实验显示当序列长度超过一定阈值后所有框架的吞吐量都会断崖式下降区别只在于下降的拐点位置。TensorRT-LLM 因为量化支持更好拐点出现得最晚vLLM 通过 PagedAttention 的显存管理拐点位置居中TGI 的拐点出现最早但下降曲线最平缓。3.3 框架选型的决策框架基于论文的结论和自己的实践经验我整理了一个框架选型的决策框架供大家参考。第一步是明确业务场景的负载特征。如果你的请求以短序列为主框架之间的差异不会太大选社区活跃、部署简单的即可。如果长序列请求占比高就需要重点关注框架的显存管理和 prefill 优化能力。第二步是评估硬件约束。如果你用的是较新的 NVIDIA GPUTensorRT-LLM 的性能优势值得投入编译成本。如果硬件型号较杂或者需要快速适配新模型vLLM 的通用性更有优势。第三步是考虑运维成本。TensorRT-LLM 的编译流程需要专门的 CI/CD 支持模型更新时需要重新编译和验证。vLLM 和 TGI 的模型更新则简单得多基本是改配置重启的事。第四步是看团队技术栈。如果团队已经有成熟的 TensorRT 使用经验继续用 TensorRT-LLM 是自然选择。如果团队更熟悉 Python 生态vLLM 和 SGLang 的上手成本更低。一个常见的误区是“选一个框架用到底”。实际上很多生产环境会同时部署多个框架根据请求类型路由到不同的后端。比如对话类请求走 vLLM代码生成类请求走 SGLang批量摘要类请求走 TensorRT-LLM。这种混合部署策略在论文的实验中也得到了验证端到端性能比单一框架提升明显。4. 关键优化方法的收益边界什么时候该用什么时候不该用4.1 连续批处理的真实收益与调度开销连续批处理Continuous Batching是 LLM Serving 领域最核心的优化方法之一它的基本思想是不等一个 batch 里的所有请求都完成而是动态地把新请求插入到正在执行的 batch 中已完成请求的位置立即释放给新请求。论文的实验证实了连续批处理在大多数场景下都能带来显著的吞吐提升但同时也揭示了一个容易被忽略的问题调度开销。当请求到达率极高、请求长度差异极大时调度器需要频繁地做插入和释放操作这些操作本身会消耗 CPU 资源甚至成为瓶颈。论文给出的经验数据是当每秒请求数RPS超过一定阈值具体阈值取决于 CPU 性能和请求长度分布连续批处理的调度开销会开始侵蚀吞吐收益。在这个拐点之后适当增大批处理窗口、减少调度频率反而能获得更好的端到端性能。我在实际生产中也遇到过类似情况。当时线上服务用的是默认的连续批处理配置在流量高峰期GPU 利用率只有 60% 左右但 CPU 已经跑满了。后来把调度器的批处理窗口从 10ms 调整到 50msGPU 利用率提升到了 80% 以上P99 延迟反而略有下降。这个案例说明连续批处理不是“开了就完事”调度参数的调优同样重要。4.2 PagedAttention 的显存管理逻辑与碎片问题PagedAttention 是 vLLM 的核心创新它把 KV Cache 分成固定大小的 block 来管理就像操作系统的虚拟内存分页一样。这样做的好处是显存碎片大幅减少可以支持更高的并发数。但论文指出PagedAttention 的收益并不是无条件的。在序列长度分布比较集中的场景下PagedAttention 的显存管理开销block 分配、页表维护会抵消一部分碎片减少带来的收益。而在序列长度差异极大的场景下PagedAttention 的优势才真正体现出来。论文的实验数据显示当序列长度标准差较小时PagedAttention 相比传统连续显存分配的吞吐提升在 5%-10% 左右当序列长度标准差较大时提升幅度可以超过 30%。这个数据很有参考价值因为它告诉我们如果你的业务场景中请求长度比较均匀PagedAttention 带来的收益可能没有想象中那么大。另外PagedAttention 的 block size 选择也是一个需要调优的参数。block size 太小页表开销大block size 太大内部碎片多。论文建议的起始值是 16然后根据实际序列长度分布做调整。我在实践中发现对于大多数对话场景block size 设为 16 或 32 都能取得不错的效果但如果是长文档处理场景block size 设为 64 甚至 128 可能更合适。4.3 Chunked Prefill 的适用条件与延迟影响Chunked Prefill 是近两年比较热门的优化方法它的核心思想是把长序列的 prefill 阶段拆成多个 chunk每个 chunk 和 decode 请求一起组成 batch从而避免长 prefill 阻塞 decode 请求。论文对 Chunked Prefill 的评估非常细致结论也很有启发性。首先Chunked Prefill 确实能显著降低长序列请求对短序列请求的延迟影响。在混合负载场景下开启 Chunked Prefill 后短序列请求的 P99 延迟可以降低 40% 以上。但代价是长序列请求自身的 TTFT 会略有增加因为 prefill 被拆成了多个 chunk每个 chunk 之间需要等待调度。论文的数据显示长序列请求的 TTFT 增加幅度在 10%-20% 之间具体取决于 chunk size 和调度策略。所以 Chunked Prefill 的适用条件很明确当你的服务同时处理长序列和短序列请求且短序列请求对延迟敏感时Chunked Prefill 是值得开启的。但如果你的服务只处理单一类型的请求或者所有请求的序列长度都比较接近Chunked Prefill 带来的收益就很有限了。还有一个容易被忽略的点Chunked Prefill 的 chunk size 选择需要和连续批处理的 batch size 协同考虑。chunk size 太小调度次数增加CPU 开销上升chunk size 太大又失去了拆分 prefill 的意义。论文建议的起始配置是 chunk size 设为 512 或 1024然后根据实际负载调整。4.4 投机解码的加速比与接受率关系投机解码Speculative Decoding是另一种常见的加速方法它用小模型快速生成多个候选 token然后用大模型并行验证从而减少大模型的前向次数。论文对投机解码的评估揭示了一个关键规律加速比高度依赖于接受率acceptance rate。当接受率高于 70% 时投机解码能带来 1.5 倍到 2 倍的加速当接受率低于 50% 时投机解码反而可能拖慢整体速度因为验证失败后的回滚和重新生成会带来额外开销。接受率取决于两个因素小模型和大模型的分布匹配程度以及任务本身的确定性。对于代码生成、结构化输出等确定性较强的任务接受率通常较高对于创意写作、开放域对话等任务接受率则较低。论文还指出投机解码的收益在不同框架上的实现差异很大。有些框架的投机解码实现没有做好 batch 内的对齐导致验证阶段的并行度不够加速效果大打折扣。所以如果你打算用投机解码建议先在目标框架上做小规模测试确认实际加速比后再大规模部署。5. 系统设计中的工程细节论文里不会写但生产环境必须面对的问题5.1 多副本调度与负载均衡的真实挑战当单副本无法满足吞吐需求时多副本部署是必然选择。但论文指出多副本调度远不是“加个负载均衡器”那么简单。第一个挑战是请求路由的粒度。如果按请求级别做轮询路由可能会导致某些副本的 KV Cache 命中率很低因为同一个会话的多个请求可能被路由到不同副本。如果按会话级别做一致性哈希路由虽然能提高 KV Cache 命中率但会导致负载不均衡因为不同会话的请求量差异很大。论文对比了几种路由策略的实际效果。结果显示在对话场景下会话级一致性哈希的端到端吞吐比请求级轮询高出 15%-25%但 P99 延迟的波动也更大。论文建议的做法是用会话级哈希做基础路由同时监控各副本的负载当某个副本过载时把新会话临时路由到低负载副本。第二个挑战是副本间的 KV Cache 迁移。当一个副本需要下线维护或者扩容时上面的 KV Cache 需要迁移到其他副本否则正在进行的会话会中断。论文讨论了两种迁移策略主动迁移和被动重建。主动迁移是把 KV Cache 数据传输到目标副本适合会话状态重要的场景被动重建是让目标副本重新计算 KV Cache适合会话状态可重建的场景。两种策略的 trade-off 很明显主动迁移节省计算但消耗网络带宽被动重建节省带宽但消耗计算资源。5.2 KV Cache 的显存管理与换出策略KV Cache 的显存管理是 LLM Serving 中最棘手的工程问题之一。论文用了一整节来讨论这个问题因为它的影响太大了——显存不够要么降低并发数要么把 KV Cache 换出到 CPU 内存或 SSD而换出又会带来延迟。论文的实验显示KV Cache 换出到 CPU 内存的延迟开销在 5ms 到 20ms 之间具体取决于 PCIe 带宽和传输数据量。换出到 SSD 的延迟开销则高一个数量级通常在 50ms 以上。所以换出策略的选择需要根据 SLO 来定如果 SLO 允许 100ms 以上的延迟波动换出到 SSD 是可以接受的如果 SLO 要求 P99 延迟在 50ms 以内换出到 CPU 内存已经是极限了。论文还讨论了一个容易被忽略的问题KV Cache 的换出优先级。不是所有 KV Cache 都同等重要。正在活跃使用的 KV Cache 不应该被换出否则会触发 page fault导致延迟飙升。论文建议的做法是给每个 KV Cache block 维护一个最近使用时间戳优先换出最久未使用的 block。同时对于即将被换出的 block可以提前做预取减少 page fault 的影响。我在实际生产中的经验是KV Cache 换出策略需要和请求调度策略协同设计。如果调度器知道某些请求即将到达可以提前把相关的 KV Cache 预取回 GPU这样当请求真正到达时就不需要等待换入。这种“预测性预取”的策略在论文中没有详细讨论但在实际场景中效果很好。5.3 异构硬件混部的调度策略论文最后讨论了异构硬件混部的场景这是很多生产环境都会遇到的情况手头有不同型号的 GPU性能差异大显存容量也不同。如何把这些异构资源统一调度是一个很有挑战的问题。论文提出的策略是“能力感知调度”把请求按照计算需求和显存需求分类然后路由到最适合的硬件上。比如长序列 prefill 请求路由到计算能力强、显存大的 GPU 上短序列 decode 请求路由到延迟低、显存小的 GPU 上。这种策略的核心思想是“让合适的硬件做合适的事”而不是简单地按比例分配请求。论文的实验数据显示能力感知调度相比简单的轮询调度端到端吞吐可以提升 20%-30%P99 延迟降低 15% 左右。但代价是调度器的复杂度大幅增加需要实时监控各硬件的负载和显存状态并做出动态决策。异构混部还有一个容易被忽略的问题模型版本的一致性。如果不同硬件上部署的模型版本不同路由时需要确保请求被路由到正确版本的副本上。论文建议的做法是给每个模型版本打标签路由时同时匹配模型版本和硬件能力。6. 从论文到生产我的落地经验与踩坑记录6.1 框架选型的实际决策过程读完论文后我在负责的一个推理服务项目上重新做了一次框架选型。这个项目的负载特征是对话类请求占 60%代码补全类请求占 30%文档摘要类请求占 10%。硬件配置是 8 张 A100 80GB 和 4 张 A30。按照论文的决策框架我首先排除了 TensorRT-LLM因为团队没有 TensorRT 的使用经验而且模型更新频繁编译成本太高。然后在 vLLM 和 SGLang 之间做选择。考虑到代码补全类请求的前缀共享程度高SGLang 的 RadixAttention 有天然优势但对话类请求的负载更均衡vLLM 的通用性更好。最终的方案是混合部署对话类请求走 vLLM代码补全类请求走 SGLang文档摘要类请求走 TGI因为 TGI 的稳定性最好适合长序列场景。这个方案在论文的实验数据中也能找到支撑不同框架在不同场景下的优势确实存在混合部署能取长补短。实际运行下来端到端吞吐比之前单一 vLLM 部署提升了约 35%P99 延迟降低了约 20%。但运维复杂度确实增加了需要维护三套框架的配置和监控。所以这个方案适合有一定运维能力的团队如果团队规模较小建议还是先用单一框架把调优做透。6.2 参数调优的踩坑记录在参数调优上我踩过几个印象深刻的坑这里分享出来供大家参考。第一个坑是连续批处理的 batch size 设置。一开始我按照论文建议的起始值设置结果发现 GPU 利用率上不去。后来发现是因为请求长度分布比论文实验中的更集中导致 batch 内的请求几乎同时完成批处理窗口利用率低。把 batch size 调大后GPU 利用率明显提升。这个经验说明论文的建议值只是起点实际调优必须结合自己的负载特征。第二个坑是 PagedAttention 的 block size。我一开始用了默认的 16在对话场景下表现不错。但后来上线了一个长文档处理功能发现显存碎片率飙升。把 block size 调到 64 后碎片率明显下降。这个经验说明block size 需要根据序列长度分布动态调整不能一套配置用到底。第三个坑是 Chunked Prefill 的 chunk size。我一开始设了 256结果发现长序列请求的 TTFT 增加太多用户体验下降。调到 1024 后TTFT 恢复到可接受范围同时短序列请求的延迟改善仍然明显。这个经验说明chunk size 的选择需要在长序列 TTFT 和短序列延迟之间找平衡。6.3 监控与告警体系的搭建论文没有详细讨论监控和告警但这在生产环境中至关重要。我基于论文的指标维度搭建了一套监控体系这里简要分享。核心监控指标包括TTFT、TPOT、P99 延迟、GPU 利用率、显存占用率、KV Cache 命中率、请求队列长度、调度器 CPU 使用率。这些指标需要按请求类型、按模型版本、按硬件型号分别统计才能定位到具体问题。告警策略上我设置了三级告警一级告警是 P99 延迟超过 SLO 的 1.5 倍二级告警是 GPU 利用率持续低于 50% 或高于 95%三级告警是 KV Cache 命中率低于阈值。一级告警需要立即处理二级告警需要关注趋势三级告警用于容量规划。还有一个容易被忽略的监控项请求的输入输出长度分布。这个分布的变化往往预示着业务场景的变化比如突然出现大量长序列请求可能是某个新功能上线了。提前发现这种变化可以及时调整资源配置避免服务过载。6.4 论文结论的验证与修正最后分享一下我对论文部分结论的验证结果。论文说 TensorRT-LLM 在长序列 prefill 场景下比 vLLM 快 20%-30%我在自己的测试中验证了这个结论但发现差距的大小高度依赖于序列长度。当序列长度在 2K 以下时差距只有 10% 左右当序列长度超过 8K 时差距才扩大到 25% 以上。所以如果你的业务场景中长序列请求不多TensorRT-LLM 的性能优势可能没有论文中那么明显。论文说 SGLang 在前缀共享程度高的场景下优势明显我在代码补全场景中验证了这一点但发现优势的大小还取决于请求的并发模式。当并发请求的前缀高度相似时SGLang 的吞吐优势可以达到 40% 以上当并发请求的前缀差异较大时优势缩小到 10% 以内。这个发现说明SGLang 的收益不是无条件的需要业务场景的配合。论文说 Chunked Prefill 能降低短序列请求的 P99 延迟 40% 以上我在实际测试中得到的数字是 30%-35%略低于论文数据。分析原因可能是我的负载中短序列请求的占比没有论文实验中那么高导致 Chunked Prefill 的收益被稀释。这个差异提醒我论文的实验结论需要结合自己的负载特征做修正不能直接照搬。整体来说这篇论文的结论在我的生产环境中大部分得到了验证但具体的数值和拐点位置需要根据实际情况调整。论文最大的价值不是给出一个“标准答案”而是提供了一个系统性的分析框架帮助我理清了 LLM Serving 中各种优化方法的适用条件和 trade-off。如果你也在做推理服务的部署和优化建议把这篇论文当作参考手册在实际遇到问题时翻出来对照分析而不是指望它给出可以直接套用的配置。