选 vLLM 还是 SGLang,先把问题缩小到自己的负载。交互式助手关心首 token 和流式输出是否稳定,批处理更关心每秒能完成多少请求。两种负载可能给出不同的选型结果。
本文解读一组公开的单卡 L4 对照数据,并给出一套可在自己的环境里复跑的压测命令。公开测量由原项目完成,本站提供指标解读与复跑方案。
单卡 L4 对照数据怎么读
公开案例在 NVIDIA L4 24 GB 上运行 Qwen2.5-7B-Instruct FP16,短输入不超过 256 token,输出上限 128 token。报告使用 vLLM 0.8.5 和 SGLang 0.4.6,两个服务的显存比例和 CUDA Graph 设置不同。以下数据对应这一组配置,可追溯到Inference Bench 的报告与原始记录。
| 短输入场景 | 指标 | vLLM | SGLang |
|---|---|---|---|
| 并发 1 | 首 token 延迟 | 70 ms | 119 ms |
| 并发 64 | TTFT P50 | 582 ms | 314 ms |
| 并发 64 | 输出吞吐 | 831 token/s | 914 token/s |
| 并发 64 | 端到端延迟 P95 | 10,222 ms | 9,123 ms |
这组实验的低并发首 token 和高并发输出吞吐指向不同的选择。版本、GPU、推理配置和流量换了,都需要重新测。表中的端到端 P95 覆盖整次响应,不能当作 TPOT 读取。
把每行数据放回对应的并发和负载。并发为 1 时,TTFT 更接近请求在空闲服务里的体验。并发增大后,排队和批调度开始影响尾延迟。即使总输出吞吐上升,也要同时看失败率和 P95,因为少量慢请求足以让交互产品变差。
固定变量再跑两套服务
同一块 GPU 上依次启动两个引擎,每轮结束后停止前一个服务并确认显存释放。记录 GPU、驱动、引擎版本、模型与 tokenizer 的本地快照、精度、量化格式和注意力后端。先固定 FP16、同一模型快照、相同上下文上限和输出预算,再分别测试短输入与长输入。需要评估真实前缀复用时,另开一组明确标记的热缓存测试。
1 2 3 4 5 6 7 8 9 10 11 12 | # 在两套隔离的 Linux 环境中分别启动,按顺序运行。 # MODEL 指向双方读取的同一个本地模型快照,示例可用 Qwen2.5-1.5B-Instruct。 export MODEL=/absolute/path/to/model-snapshot # A: vLLM vllm serve "$MODEL" --served-model-name bench-model \ --host 127.0.0.1 --port 8000 --dtype float16 --max-model-len 4096 # B: 停止 A 后,启动 SGLang python -m sglang.launch_server --model-path "$MODEL" \ --served-model-name bench-model --host 127.0.0.1 --port 8000 \ --dtype float16 --context-length 4096 |
在独立的压测客户端环境使用同一版本的 SGLang bench serving,对两端都发 /v1/completions 请求。下例用同一个 backend 走相同的请求路径。先确认所装版本的 –help 与命令一致,并用小样本检查模型别名、输出长度和错误率。命令所用参数可查阅SGLang bench serving 官方文档。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/usr/bin/env bash set -euo pipefail engine=${1:?Pass vllm or sglang} : "${MODEL:?Set MODEL to the shared local model snapshot}" mkdir -p results for input in 256 2048; do for concurrency in 1 8 16; do for rep in 1 2 3; do python -m sglang.benchmark.serving \ --backend sglang-oai --base-url http://127.0.0.1:8000 \ --model bench-model --tokenizer "$MODEL" \ --dataset-name random --random-input-len "$input" \ --random-output-len 128 --random-range-ratio 1 \ --num-prompts 96 --seed "$rep" --warmup-requests 8 \ --max-concurrency "$concurrency" \ | tee "results/${engine}-in${input}-c${concurrency}-r${rep}.log" done done done |
例如保存为 bench.sh,分别在对应服务运行时执行 bash bench.sh vllm 与 bash bench.sh sglang。在同一组内按重复编号配对,并记录实际输入和输出 token 数。两个引擎如果提前停止的比例不同,应先检查 EOS 和客户端的停止策略,不能直接把平均输出更短的服务视为更快。此命令是复跑模板,负载与上面的公开数据并不完全相同。
结果表与判定规则
| 记录项 | 取数方法 | 如何判读 |
|---|---|---|
| TTFT P50/P95 | 客户端发送请求到首个有效生成内容 | 分开看空载和高并发。只在高并发恶化时优先看排队与批调度。 |
| TPOT P50/P95 | 对输出超过一个 token 的请求,按首 token 到最后 token 的耗时除以剩余 token 数 | 衡量每个请求的平均生成节奏。若关注卡顿,还应看相邻输出的间隔。 |
| 输出 tokens/s | 测量窗口内成功生成的 token 总数除以窗口秒数 | 别把输入和输出合并后的吞吐当成生成吞吐。 |
| 成功数、实际输出长度、达标请求数 | 记录成功/总请求,以及同时满足 TTFT 与 TPOT 门槛的请求数 | 失败请求计入总请求。比较同一门槛下每秒达标请求数。 |
每个单元格保留三次结果,优先报告每轮的 P95 及跨轮波动。先用业务给出的延迟门槛筛掉不达标配置,再比较达标吞吐和显存余量。固定并发是起点,若线上流量有突发,再加一组固定到达速率测试,避免把客户端限流的结果当成服务容量。
需要先确认框架功能和架构差异,可查阅vLLM 与 SGLang 选型对比。若两套服务都在长 prompt 与短请求混跑时出现尾延迟,可接着做PD 分离的 KV Cache 瓶颈排查。
汤不热吧