恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

vLLM与SGLang性能瓶颈分析:从指标到排查路径

  • 首页
  • 资讯中心
  • /
  • vLLM与SGLang性能瓶颈分析:从指标到排查路径

相关资讯

TypeScript 项目编译慢?5分钟优化指南 2026/10/16 6:57:40
Ascend C 矢量计算多核 Tiling 切分策略实战:以 vector_tiling_strategy 样例解析核间与核内数据分配 2026/10/16 6:57:40
Java高校社团活动管理系统毕设:架构设计与实战指南 2026/10/16 6:57:40

最新资讯

Agency智能体工程化:跨平台AI编程的生产级架构实践
输入增量状态空间MPC公式对比与Matlab代码实现
OpenCode CLI 安装教程与强大插件推荐:前置条件、插件地址与安装方法全解析
嵌入式UART串口驱动开发实战:从波特率计算到中断DMA与环形缓冲区设计
基于MP2642GR-Z与STM32的2S磷酸铁锂电池均衡方案设计与调试
被举报计划审核后台设计:信息架构与状态流转实战

今日推荐

Java八种基本类型深度解析:从内存布局到实战选型
基础:常用快捷键——IDEA、VS Code、PyCharm 与 Linux 终端效率速查
解决ultraedit下verilog .v文件中文注释乱码:把编码配置改到TaoToken辅助排查

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

vLLM与SGLang性能瓶颈分析:从指标到排查路径

发布时间:2026/10/16 6:57:40
vLLM与SGLang性能瓶颈分析:从指标到排查路径 性能分析这件事做推理框架的应该都有体会vLLM 和 SGLang 參數看着差不太多但同样的模型、同样的显卡、同样的并发跑出来的吞吐和延迟经常是天壤之别。更头大的是一旦性能不行日志里全是“OOM”“timeout”根本分不清是显存不够、调度等待太久还是 GPU 计算饱和了。这篇东西就把我这段时间在 vLLM 和 SGLang 上做瓶颈分析的经验捋一遍——从指标怎么读、工具怎么用、再到日志怎么对给你一套能直接抄作业的排查路径适合刚开始做推理服务优化、或者被线上延迟问题逼到想换框架的人参考。1. 先搞清推理链路上有哪些环节1.1 别把“性能瓶颈”当成一个笼统的词我见过不少人一上来就盯着GPU-Util看看到 80% 就觉得卡没吃满看到 30% 就认为模型不行。实际上在大模型推理里GPU 利用率只是最后一步的结果前头还堆着一大堆事请求预处理、队列等待、调度决策、KV Cache 命中、输入输出张量搬运这些都会影响最终的性能。如果不把这些环节拆开你调什么都只是盲打。所以做系统性分析的第一步是先把推理链路切成几段挨个查请求接入与前置处理Prompt 的预处理、长度统计、分词这一段如果是纯 CPU 逻辑很容易被忽略。调度与批处理框架怎么把多个请求拼成一个 batch怎么分配显存空间这直接决定 GPU 有没有吃饱。显存分配与 KV CacheKV Cache 能不能被复用、会不会碎片化几乎决定了你能支撑多大并发。张量计算Prefill 阶段和 Decode 阶段的计算模式完全不同瓶颈位置也因此不同。输出与释放生成结束后显存怎么归还会不会卡住下一个请求。在 vLLM 和 SGLang 这两只框架里这五段都有各自的实现细节。vLLM 的优势在连续批处理和显存管理它把页面调度做得很细SGLang 则在请求调度上玩出了更灵活的编排尤其适合带复杂约束生成的场景。但不管底层怎么实现分析流程都是这五段逐层排查。1.2 框架选型决定了你该盯哪些点我在做性能分析之前一般会先确认自己在用哪套版本的框架、哪个版本的 CUDA因为这些直接影响后续的 profile 工具能不能用、日志字段能不能对上。vLLM 的核心机制是 Continuous Batching 和 PagedAttention因此它对显存碎片问题特别敏感你去查性能问题的时候第一优先级应该看 KV Cache 的命中率、显存块block利用率以及调度器是否会频繁阻塞等待空闲块。SGLang 这边它的亮点在于对请求进行结构化调度以及在长 prompt 场景下的缓存复用机制。你在 SGLang 上做分析重点要放在它的调度耗时上当一个请求进来之后它花了多长时间做路由决策、有没有出现请求互相阻塞的排队点。这里有个常见的经验误区很多人以为 vLLM 快就是因为它用了 PagedAttentionSGLang 快就是因为它做了 RadixAttention于是一遇到性能瓶颈就去改显存分配策略。但我在实测中发现多数性能突然劣化其实不是来自显存分配而是来自调度器的锁竞争和队列堆积。这个后面展开说分析时一定要把调度耗时单独拿出来看。只盯显存会漏掉最大的一块蛋糕。2. 四大类指标怎么读不要被平均延迟骗了2.1 延迟要分层TTFT、TPOT、ITL 一个都不能省大模型推理不像传统 Web 请求不是说一个 request 返回一个 response 就完了。它是有“首字”和“后续字”之分的我习惯把延迟拆成三块TTFTTime To First Token从请求进入系统到输出第一个 token 的时间。这阶段基本对应 Prefill 计算prompt 越长TTFT 越大。TPOTTime Per Output Token生成阶段每产出一个 token 的平均时间反映 Decode 的吞吐能力。ITLInter-Token Latency前后两个 token 输出之间的间隔。ITL 波动大说明生成过程不稳定可能跟缓存命中、动态批处理有关。比如 TTFT 高但 TPOT 低说明 prefill 是大头你需要优先解决长 prompt 场景的 prefill 性能比如做 prompt 缓存或者缩短 prefill 长度TTFT 正常但 TPOT 高说明 decode 阶段卡住了要优先看批处理大小和显存带宽是否够用。这个诊断思路在 SGLang 和 vLLM 上都成立。有朋友问我“为什么我看平均延迟还行但线上 P99 延迟总是超时”因为这些测试框架里有些 Benchmark 工具默认会等所有请求都跑完才统计而线上压力是动态到达的平均延迟把偶发的大尾巴平均掉了你看均值压根看不出问题。所以我建议你们做性能对比时只看 P50、P95、P99 三个分位数P99 能测出你在压力下真实的行稳定性。2.2 吞吐量要看“有效吞吐”别被纯 batch 吞吐忽悠吞吐量最常被滥用的指标就是“每秒生成多少 token”。别看它数字好看如果你为了堆这个数字把每个请求的响应时间都拖到用户无法接受那就没有意义。在推理框架里我更看重有效吞吐Goodput也就是单位时间内满足延迟要求例如 P99200ms的请求数量。vLLM 和 SGLang 在跑高并发时都会出现一个现象GPU 算力还没满但请求排队时间已经增长导致整体有效吞吐下降。这通常是因为调度器在每个 batch 中塞了太多“长尾请求”大家都被慢请求拖住了。这里的解法不一定是你 GPU 不够而是你要给请求设置合理的最长生成长度max_tokens尽量把同等量级生成长度的请求分到一个 batch 里减少经过慢请求拖慢整个批次的情况。2.3 显存占用没那么简单重点看 KV Cache 和碎片率在分析显存瓶颈时我一般不只看nvidia-smi显示的显存占用因为那个数字包括模型权重和临时计算缓冲不能直接反映 KV Cache 的压力。我更喜欢通过框架自带的 metrics 来看这几个值KV Cache 使用量占显存的比例超过 95% 一般就会出现调度阻塞。空闲块Free Blocks变化情况空闲块长期忽高忽低说明碎片化严重。Preemptions/Recomputations 计数这个指标一高说明显存经常不足导致请求被抢占或重新计算。我之前在排查一个 OOM 问题时观察nvidia-smi显示显存还有 5GB 余量但 vLLM 仍然报显存不足。原因是 KV Cache 使用的显存快满剩下的显存空闲但没法被 PagedAttention 使用。这个坑特别典型你要用框架的内部 API 去查而不是只看显卡的剩余显存。2.4 算力利用率要结合 Prefill/Decode 阶段来算GPU 利用率超过 90% 不意味着性能已经最优它还取决于算力用在了哪个阶段。Prefill 阶段是典型的稠密计算用的是 FP16 矩阵乘能很好打满 GPUDecode 阶段是典型的访存瓶颈矩阵乘只有很小的 batch大部分时间在搬数据GPU 利用率看着可能不低但实际有效算力很低。这也是为什么区分 Prefill 和 Decode 很关键。你在分析一个纯 Decode 请求为主的场景里看到 GPU-Util 80% 说不定已经到边界了而在 Prefill 为主的场景里GPU-Util 只有 60%那大概率是调度问题或内存读带宽卡住了。要算清楚的话建议把 Prefill 和 Decode 的耗时分别从框架日志里拿出来再对照显存带宽和数据量估算峰值。我用过的简单办法是total_output_tokens / total_decode_time_sec然后跟硬件理论带宽对比如果差距超过两倍就说明计算效率有问题。3. 实操三种方法快速定位性能瓶颈3.1 方法一用统一的 Benchmark 脚本做基线测试做瓶颈分析之前一定要先有一份可复现的基线数据。我建议你们准备一个固定 prompt、固定 max_tokens、固定并发数的脚本优先跑小并发比如 1 并发再跑高并发比如 64 并发。通过对比不同并发下的延迟分位数观察哪个并发点开始出现明显的趋势拐点这就是入口瓶颈的位置。并发从 1 增加到 8TTFT 上升缓慢从 8 增加到 32TTFT 直线飙升说明调度器的批处理能力已经到顶此时 GPU 可能还没跑满。要验证这一点把并发固定到 32把模型换成一个更小的模型看 TTFT 是否下降如果并没怎么下降基本能断定瓶颈在调度而非计算。SGLang 和 vLLM 都自带有 benchmark/run 之类的工具但我的习惯是写一个自己的 Python 脚本用 OpenAI 兼容接口压测顺便把每个请求的 TTFT、TPOT、ITL 都记录到 CSV 里后面用 pandas 直接算分位数。直接用框架自带的工具做基线是可以的但如果要做线上对比它的负载模式不一定符合你的实际场景。下面是简化版的压测脚本结构import requests import time import statistics prompt 讲一个关于科技发展的故事 url http://localhost:8000/v1/completions headers {Authorization: Bearer EMPTY} data {model: test-model, prompt: prompt, max_tokens: 256} latencies [] for i in range(100): start time.time() resp requests.post(url, jsondata, headersheaders) elapsed time.time() - start latencies.append(elapsed) time.sleep(0.05) # 模拟真实请求间隔 print(avg:, statistics.mean(latencies)) print(p95:, sorted(latencies)[int(len(latencies)*0.95)])这个脚本只用于定基线实际压测我一般会结合负载生成工具去构造更复杂的并发模型但先把串行和简单的并发跑一遍能最快看出框架基础吞吐量有没有异常。3.2 方法二用 Profiler 工具看 Compute Kernel 耗时在确认调度不是瓶颈之后下一步是深入 GPU Kernels直接用 Nvidia Nsight Systemsnsys或者 Nsight Compute 分析。下面是一个查看 Kernel 耗时的方法nsys profile -o trace_output --force-overwrite true -t cuda,nvtx -- python benchmark.py跑完之后看 timeline 图重点关注Prefill Kernel 和 Decode Kernel 分别占用多少时间。是否存在 GPU 空闲等待也就是 GPU 没有工作但也没有 kernel 的 gap 时间。这个 gap 大概率来自 CPU 端调度等待或数据传输。如果你的 GPU 利用率高但 gap 仍然存在多半是数据从 CPU 搬 GPU 的瓶颈。单个 kernel 的启动开销。如果 Kernel 启动频率特别高而每次计算量都很小那么你需要增大 batch size减少启动次数。对于 SGLang 和 vLLM因为框架内部都有 Python 调度线程用 nsys 能看到很大的 CPU 执行时间。我经常在这些阶段的 profile 日志里看到调度函数加锁耗时几百毫秒这在多机多卡环境下更严重。判断时重点看 CPU 侧有没有长时间等待不是torch操作而是一堆select、sleep这种系统调用。如果是这样问题基本指向了框架内部队列处理和锁竞争。3.3 方法三用框架自带的日志和 Prometheus 指标进行运行时观察线上系统我一般不随便用 profiler因为附加开销不小日常监控我用框架公开的指标来判断。vLLM 和 SGLang 都暴露了 metrics比如vllm_generation_tokens_total、request_queue_time、request_cache_hit_rate之类。你把这些记录到 Prometheus 后可以很直观看到瓶颈演变过程。我推荐重点盯这几个指标queue_time_p50_p99请求在调度队列里等待的时间数值一高说明调度已经变成瓶颈最简单的方法是提高并发到加大调度压力然后看吞吐是否还有增长空间。cache_hit_rate缓存命中率命中率高说明有大量重复 prompt 前缀你的 KV Cache 压力是虚设应该考虑缩小缓存以换取更多 batch 空间。preemptions每秒抢占次数大于 0 就说明显存不足这时就不要再追求更大 batch需要限制max_num_seqs或max_model_len。我把这些指标和策略对齐到了下面这张表里指标现象大概率瓶颈初步建议queue_time 很高GPU 利用率低调度器瓶颈调大max_num_seqs调整批处理窗口检查锁竞争cache_hit_rate 很高但 OOM 频发KV Cache 设定不合理减小 max_model_len调整缓存策略preemption 计数持续增长显存不足降低并发停止适用静态 batch 拼接GPU 利用率高但吞吐低解码阶段带宽受限减小 batch 大小或改用更高显存带宽的 GPUTTFT 高TPOT 正常prefill 阶段耗时过长考虑 prompt 缓存或拆分 prefill 请求4. 高频问题和对应的调整思路4.1 现象显存用不完但 OOM 不断这类问题在 vLLM 上尤其多。表面上是显存不够实际是 KV Cache 的分配策略不够灵活。vLLM 在初始化时会根据你的gpu_memory_utilization参数预留一部分显存给模型权重和 KV Cache如果此前设置了过高的保留比例那么实际可用的 KV Cache 很小并发稍微上去你就 OOM。解决办法不是调低gpu_memory_utilization而是先留足够的余量给计算缓冲和中间结果不要试图把显存利用率拉满。我之前实际踩过一次把一个 70B 模型布置在 A100 上gpu_memory_utilization0.95单请求正常一上并发就 OOM。把参数降到 0.85 后连续跑 60 分钟无 OOM吞吐反而提升了 18%因为系统不再频繁做 KV Cache 整理和抢占。如果你用的是 SGLang情况类似但它里面的显存管理逻辑略有不同在调度阶段可能更细建议先看是否启用了 RadixCache 并且缓存 token 前缀过长导致 KV Cache 占用膨胀阻塞了新建请求。这种场景下我通过设置更小的--prefix-caching开关或在较高并发时禁用它来减小缓存压力。4.2 现象并发提高延迟不降反升这种通常不是计算慢而是排队慢。因为你加了并发框架会把更多请求塞到同一个 batch 里每个请求生成长度不同系统要等这个 batch 里最慢的请求结束才能释放资源。处理方法是调整批大小和调度策略。vLLM 里设置max_num_seqs要结合平均生成长度来算。举个例子如果你的平均生成长度是 512 token那么一个 batch 里塞 32 个请求总的生成序列规模是 16K token。如果显卡是 A100一个 batch 最多能塞到 512 个 sequence 也不用担心延迟但当吞吐上来之后你会发现 decode 阶段的延迟大幅增长因为解码取决于内存带宽而不是算力超过一定输入长度后带宽成为瓶颈。我的建议是分步测试把max_num_seqs从 8 逐步增加到 64每次记录 P99 延迟和吞吐选择一个“吞吐提升最大且 P99 不翻倍”的拐点作为最终配置。这个拐点在不同框架里差别不小所以一定要在自己的环境里实测。4.3 现象缓存命中率高但首 token 延迟没有明显下降理论上命中率高prefill 会很快但如果 TTFT 仍然高说明缓存命中的是 KV Cache但你在应用层走的是全量 prompt框架无法直接读取正确的 Cache 索引还是得做大量组查。这种在 SGLang 里更明显因为它的 prefix caching 机制需要 prompt 前部文本完全一致才能复用。解决方案是重新设计你对用户输入的处理方式把 prompt 里的固定系统提示词和动态字段拆开避免把随机数据塞到前缀里。比如把系统 prompt 固定住、加分隔符而用户问题放在最后一段。这样结构化的固定前缀才能被框架当成缓存键命中。我见过一个线上服务把用户 ID 拼进了 prompt 前缀导致缓存命中率降到 2%性能直接崩掉把前缀顺序调整后命中率回到 80%。4.4 现象单机性能还行一到多卡就出现明显退化多卡推理瓶颈很多出现在通信上也就是张量并行Tensor Parallelism带来的 AllReduce 开销增长。此时你会看到 GPU 利用率虽然不低但有效吞吐和单卡相比并不成比例增加甚至下降。分析时要关注通信占比指标比如每个 kernel 之后是否跟随大量 NCCL 调用。我的排查顺序是先降低并行度到一个 GPU 上跑同一模型看单卡吞吐是否合理再逐渐增加 GPU 数画出吞吐增长曲线。如果从 1 卡升到 2 卡吞吐只多了 30% 而不是 100%那基本可以断定通信瓶颈。下一步是调整通信优化参数比如启用梯度压缩、调换模型并行策略或者通过框架设置来减少通信频率。在 vLLM 和 SGLang 中都支持控制张量并行大小如果业务量没那么大不建议盲目上多卡因为多卡通信开销可能吃掉新增的算力。5. 从瓶颈到优化我常用的几个调参与取舍5.1 调对 batch size 往往比换框架效果大很多人遇到性能瓶颈第一反应就是换框架从 vLLM 换到 SGLang或者反过来。我在实际项目里做过对比在配置不当的情况下两者性能差最多 20% 到 30%但如果你把 batch size、并发限制、缓存策略调整到位同样的框架和硬件性能提升可以去到一倍以上。所以每次分析瓶颈我都先刻一套“框架调参基线”里面包括了硬件的显存带宽和算力峰值以及当前的 batch size、seq limit、并发上限。然后按顺序做三件事调整 batch size使 GPU 的访存带宽打满。调整 max_model_len避免过长序列占用大量显存块。调整调度策略启用或关闭 prefix caching明确你的 prompt 结构是否有可复用前缀。这套流程做完再来看是不是要换框架或者调精度格式FP16 转 BF16、量化顺序一定不要反。5.2 用生成长度分布指导资源配置大多数性能瓶颈来自 prompt 和生成长度分布不均匀。比如你的请求里 prompt 平均只有 200 token但 max_model_len 设成了 32768这样做直接后果是每个请求都按 32768 来预留 KV Cache 空间显存空损耗特别大。把max_model_len设为真实服务的 Max 小余量你会立刻看到并发能力明显提升。同时观察生成长度分布时我会把请求按短、中、长分类然后分别跑一次基准。这样做的原因是短请求如 128 token适合开大 batch 和高速调度长请求如 4096 token容易在 decode 阶段碰撞显存带宽。混合请求进来时我们要通过调度设置限制较长时间长尾请求被塞进普通 batch例如 vLLM 里可以限制 dispatch 策略。这个分析方法也适用于 prompt 长度如果 prompt 很长你的 prefill 很可能成为瓶颈这时要优化它方案通常是让 prompt 前缀能重用缓存比如用 SGLang 的 prefix cache想办法把重复的上下文都放在开头这样测试性能才有参考价值。5.3 优化前先做个快速收益排序性能优化有个优先级我按收益顺序排的话是这样的解决显存碎片和 KV Cache 不足问题通常能让并发能力翻倍。解决调度队列等待问题通常能让 P99 延迟直接下降 30% 到 50%。优化 batch 大小和解码阶段的内存带宽占用让有效吞吐进一步提升。最后再做 kernel 级优化和量化收益通常很小但能拿到就拿到。这也是我做性能分析报告时的标准顺序。我看到很多人在第一步还没解决的时候就在折腾量化加载最后 OOM 照样出现还把模型的精度损失了得不偿失。最后说点个人经验我在对 vLLM 和 SGLang 做性能对比时最深刻的体会是性能分析这件事最值钱的部分不是用多高级的工具而是建立一套系统化的排查顺序。先把问题切成 调度、显存、计算、通信 四块再分别用基准、日志、profiler 交叉确认一般很快就能发现真正的瓶颈。如果你一上来就盯着 GPU 利用率或者只改参数试运气很容易被表象骗。最后再分享一个小技巧每次改动只动一个参数改完立刻跑有记录的 benchmark然后把结果记录到表里。我在整理 SGLang 与 vLLM 对比数据时就是因为连续改了两个参数导致最后拿到的数据根本没法归因到单个改动上白白浪费了半天时间。性能调优是个堆数据的活慢就是快凡是靠感觉想出来的结论基本都会被线上数据打脸。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号