vllm serve meta-llama/Llama-3.1-8B-Instruct
--gpu-memory-utilization 0.85
激进配置(需要配合小 max-num-seqs)
vllm serve meta-llama/Llama-3.1-8B-Instruct
--gpu-memory-utilization 0.95
--max-num-seqs 32
markdown
**调优方法**:先用 0.85 跑通,然后每次 +0.02,直到遇到 OOM 再 -0.02。这个「刚好不 OOM」的值就是你的最优解。
### 2.2 `--max-num-seqs`(并发请求上限)
默认值: 256 V1 建议范围: 32 ~ 128(普通模型)/ 4 ~ 16(DeepSeek-V3 等大模型)
css
**这是 V0 → V1 迁移最大的坑**:V1 的 `max_num_seqs` 不能照搬 V0 的值。V1 在 warmup 时为每个 seq 预分配采样器显存,所以 256 这个默认值在 V1 下极易 OOM。
```bash
# V1 安全启动(Llama-8B 单卡)
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--max-num-seqs 64
# V1 + DeepSeek-V3(8×H100)
vllm serve deepseek-ai/DeepSeek-V3 \
--tensor-parallel-size 8 \
--max-num-seqs 16 \
--gpu-memory-utilization 0.85
判断是否需要调整:看日志里的 preemption 告警。
vbnet
WARNING: Sequence group 0 is preempted by PreemptionMode.RECOMPUTE
because there is not enough KV cache space.
→ 降低 max-num-seqs 或提高 gpu-memory-utilization
preemption 次数越多 = 实际并发超出了 KV Cache 容量 = 请求被反复踢出再重算 = 延迟暴涨。
2.3 --max-model-len(最大上下文长度)
makefile
默认值: 模型理论最大值(如 128K)
建议值: 实际业务需求的最大值
这是新手最常犯的错误 :不设 --max-model-len,vLLM 按模型 config.json 里的理论最大值预分配 KV Cache。一个声称支持 128K 上下文的模型,如果业务只需要 8K,设 128K 会浪费大量显存。
bash
# ❌ 默认:按模型理论最大值预分配,浪费显存
vllm serve meta-llama/Llama-3.1-8B-Instruct
# ✅ 按实际业务需求限制
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--max-model-len 8192
实际效果:把 max_model_len 从 131072 降到 8192,KV Cache 可用容量可提升 2-4 倍(取决于模型架构)。
2.4 --max-num-batched-tokens(批处理 token 预算)
lua
默认值: 与 max-model-len 一致
建议范围: 4096 ~ 16384
这是 Chunked Prefill 的核心控制参数。V1 默认启用 Chunked Prefill ------ 调度器优先处理 decode 请求,用剩余 token 预算处理 prefill 分块。
| 值 | 效果 | 适用场景 |
|---|---|---|
| 2048 ~ 4096 | ITL(Token 间延迟)最优,prefill 被切更碎 | 在线聊天,延迟敏感 |
| 8192 ~ 16384 | TTFT(首 Token 延迟)最优,prefill 一次处理更多 | 离线批处理 |
| = max-model-len | 接近 V0 行为(但仍优先 decode) | 简单迁移,不想调 |
bash
# 延迟敏感型(聊天机器人)
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--max-num-batched-tokens 4096 \
--max-num-seqs 128
# 吞吐优先型(文档批处理)
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--max-num-batched-tokens 16384 \
--max-num-seqs 256
2.5 优化等级 -O 参数
vLLM V1 提供 4 级优化,控制启动时间与运行性能的权衡:
| 等级 | CUDA Graph 行为 | 启动时间 | 运行吞吐 |
|---|---|---|---|
-O0 |
无 CUDA Graph | 最快 | 最低 |
-O1 |
Piecewise CUDA Graph | 较快 | 中等 |
-O2(默认) |
Full + Piecewise CUDA Graph | 较慢 | 最高 |
-O3 |
暂同 -O2 | 同 -O2 | 同 -O2 |
bash
# 开发调试用 -O0(秒级启动)
vllm serve model --optimization-level 0
# 生产用默认 -O2 即可
vllm serve model # --optimization-level 2 是默认值
避坑 :-O0 下禁用 CUDA Graph 后吞吐会下降 30-50%,仅用于「我要快速测试模型能不能加载」的场景,不要在生产环境用。
2.6 并行策略速查
| 策略 | 参数 | 何时用 |
|---|---|---|
| 张量并行 | --tensor-parallel-size N |
模型放不进单卡 |
| 流水线并行 | --pipeline-parallel-size N |
跨节点超大模型 |
| 专家并行 | --enable-expert-parallel |
MoE 模型(DeepSeek/Qwen3MoE) |
| 数据并行 | --data-parallel-size N |
多副本提吞吐 |
关键认知:数据并行的吞吐扩展效率远高于张量并行。如果单卡能放下模型,用 8×DP 比 1×TP8 吞吐高得多。
三、SGLang 六大核心参数逐一拆解
SGLang 是 DeepSeek 官方推荐的推理引擎,它在 vLLM 的参数体系上多了几个独有的调优旋钮。
3.1 --mem-fraction-static(SGLang 版显存分配)
makefile
默认值: 自动计算(保守)
建议范围: 0.80 ~ 0.92
与 vLLM 的 --gpu-memory-utilization 同概念,但 SGLang 的自动推断偏保守。看服务器启动日志:
ini
max_total_num_tokens=665690, chunked_prefill_size=8192,
max_prefill_tokens=16384, max_running_requests=4096,
context_len=65536, available_gpu_mem=13.50 GB
判断标准:
available_gpu_mem在 5-8 GB → 刚好,不用调available_gpu_mem> 10 GB → 太保守,提高--mem-fraction-staticavailable_gpu_mem< 5 GB → 太激进,降低--mem-fraction-static
bash
# 如果日志显示 available_gpu_mem=13.50 GB(太保守)
python3 -m sglang.launch_server \
--model-path deepseek-ai/DeepSeek-R1 \
--tp 8 \
--mem-fraction-static 0.90 # 从默认值提高
3.2 --schedule-conservativeness(SGLang 独有,最重要)
makefile
默认值: 1.0
建议范围: 0.3(激进) ~ 1.5(保守)
这是 SGLang 区别于 vLLM 的最大特色。它控制调度器在接受新请求时的「冒险程度」。
看 SGLang 的运行时日志:
yaml
Decode batch. #running-req: 233, #token: 370959,
token usage: 0.82, cuda graph: True,
gen throughput (token/s): 4594.01, #queue-req: 317
| 指标 | 含义 | 健康范围 |
|---|---|---|
token usage |
KV Cache 利用率 | > 0.9 |
#queue-req |
排队请求数 | 100 ~ 2000 |
#running-req |
正在处理的请求 | 接近 --max-running-requests |
诊断决策树:
lua
token usage < 0.9 且 #queue-req > 0
→ 调度器太保守,KV Cache 没用满,请求在排队
→ 降低 --schedule-conservativeness 到 0.3
token usage 接近 1.0 且频繁出现:
"KV cache pool is full. Retract requests."
→ 调度器太激进,频繁踢请求重算
→ 提高 --schedule-conservativeness 到 1.3
bash
# 离线批处理(吞吐优先,激进调度)
python3 -m sglang.launch_server \
--model-path Qwen/Qwen2.5-72B-Instruct \
--tp 4 \
--schedule-conservativeness 0.3 \
--mem-fraction-static 0.90
# 在线服务(延迟优先,保守调度)
python3 -m sglang.launch_server \
--model-path Qwen/Qwen2.5-72B-Instruct \
--tp 4 \
--schedule-conservativeness 1.3 \
--max-running-requests 128
3.3 --cuda-graph-max-bs(CUDA Graph 批量覆盖)
makefile
默认值: 160 ~ 256(视模型而定)
建议范围: 256 ~ 768
CUDA Graph 把一系列 CUDA kernel 调用录制下来重放,消除逐 kernel 提交的开销。默认只覆盖小批量------如果你的实际并发经常超过 256,增加这个值可以显著提吞吐。
bash
# 大 TP 推理场景(如 TP=8)扩大 CUDA Graph 覆盖
python3 -m sglang.launch_server \
--model-path deepseek-ai/DeepSeek-R1 \
--tp 8 \
--cuda-graph-max-bs 512 \
--mem-fraction-static 0.85 # CUDA Graph 吃显存,需同步调低
CUDA Graph + torch.compile 叠加效果(DeepSeek-V3, batch_size=1, 256 input / 32 output tokens):
| 配置 | 总延迟 | 吞吐 (token/s) |
|---|---|---|
| 无优化 | 7.322 s | 39.34 |
| CUDA Graph | 1.256 s | 229.27 |
| CUDA Graph + torch.compile | 1.011 s | 284.86 |
从 39 token/s 到 285 token/s,纯靠启动参数,不换硬件不动模型。
3.4 --max-running-requests(并发上限)
makefile
默认值: 自动计算
建议范围: 取决于显存
与 vLLM 的 --max-num-seqs 对应。如果出现 OOM:
| OOM 类型 | 调整方向 |
|---|---|
| Prefill 阶段 OOM | 降低 --chunked-prefill-size 到 4096 或 2048 |
| Decode 阶段 OOM | 降低 --max-running-requests |
| 通用 OOM | 降低 --mem-fraction-static 到 0.80 |
bash
# 长上下文场景:小 chunk、少并发、大 KV Cache
python3 -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--context-length 32768 \
--chunked-prefill-size 4096 \
--max-running-requests 64 \
--mem-fraction-static 0.88
3.5 --tp-size vs --dp-size(并行策略)
SGLang 把张量并行和数据并行分开暴露:
bash
# 数据并行优先(吞吐最大化):单卡放得下模型时
python3 -m sglang.launch_server \
--model-path Qwen/Qwen2.5-7B-Instruct \
--dp-size 8 # 8 个副本,8× 吞吐
# 张量并行(模型放不下时)
python3 -m sglang.launch_server \
--model-path Qwen/Qwen2.5-72B-Instruct \
--tp-size 4 # 4 卡拼一个模型
# DeepSeek 专用:DP Attention(MLA 架构关键优化)
python3 -m sglang.launch_server \
--model-path deepseek-ai/DeepSeek-R1 \
--tp-size 8 \
--dp-size 8 \
--enable-dp-attention
DP Attention 的原理 :MLA(Multi-head Latent Attention)的 KV Cache 只有 1 个 head,TP 无法切分,每卡存一份完整 KV Cache。开启 --enable-dp-attention 后,请求按 DP 维度分布,每张卡只维护自己那份请求的 KV Cache,显存效率大幅提升。
3.6 SGLang 专属加速选项
| 参数 | 适用场景 | 代价 |
|---|---|---|
--enable-torch-compile |
小模型 + 小批量 | 首次启动编译时间 + 显存 |
--quantization fp8 |
支持 FP8 的模型 | 精度微降 |
--enable-flashinfer-mla |
DeepSeek 模型 | 需装 flashinfer |
--speculative-algo NEXTN |
DeepSeek-V3/R1 | 需加载 draft 模型 |
--schedule-policy lpm |
共享前缀多的场景 | 调度开销 |
--enable-hierarchical-cache |
长上下文场景 | 需配置存储后端 |
bash
# DeepSeek-R1 性能全开配置(8×H200)
python3 -m sglang.launch_server \
--model-path deepseek-ai/DeepSeek-R1 \
--tp 8 \
--trust-remote-code \
--enable-dp-attention \
--dp-size 8 \
--cuda-graph-max-bs 512 \
--mem-fraction-static 0.85 \
--enable-flashinfer-mla \
--enable-torch-compile \
--torch-compile-max-bs 32 \
--speculative-algo NEXTN \
--speculative-draft SGLang/DeepSeek-V3-NextN \
--speculative-num-steps 2 \
--speculative-eagle-topk 4 \
--speculative-num-draft-tokens 4
四、vLLM vs SGLang 参数对照速查表
| 调优维度 | vLLM 参数 | SGLang 参数 | 说明 |
|---|---|---|---|
| 显存分配 | --gpu-memory-utilization |
--mem-fraction-static |
越高吞吐越大,但越容易 OOM |
| 并发上限 | --max-num-seqs |
--max-running-requests |
V1 不能用 V0 的 256 |
| 批处理 Token | --max-num-batched-tokens |
--chunked-prefill-size |
小值=低延迟,大值=高 TTFT |
| 上下文长度 | --max-model-len |
--context-length |
按实际需求设,别用理论最大值 |
| CUDA Graph | -O 优化等级控制 |
--cuda-graph-max-bs |
SGLang 可独立调整批量覆盖 |
| 张量并行 | --tensor-parallel-size |
--tp-size |
模型放不进单卡时用 |
| 数据并行 | --data-parallel-size |
--dp-size |
吞吐扩展首选 |
| 调度策略 | N/A(固定) | --schedule-conservativeness |
SGLang 独有 |
| 前缀调度 | 自动 prefix caching | --schedule-policy lpm |
SGLang 需显式开启 |
| CPU NUMA | --numa-bind |
N/A | vLLM 独有 |
| torch.compile | -O 等级内包含 |
--enable-torch-compile |
SGLang 需显式开启 |
五、三种典型场景的推荐配置
场景 A:在线聊天/Agent 服务(低延迟优先)
目标:P95 延迟 < 1s,ITL < 50ms
vLLM 配置(Llama-3.1-8B,单卡 H100):
bash
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--max-model-len 8192 \
--gpu-memory-utilization 0.85 \
--max-num-seqs 64 \
--max-num-batched-tokens 4096 \
--optimization-level 2
SGLang 配置:
bash
python3 -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--context-length 8192 \
--mem-fraction-static 0.85 \
--max-running-requests 128 \
--cuda-graph-max-bs 256 \
--schedule-conservativeness 1.2 \
--attention-backend fa3
场景 B:离线文档批处理(吞吐优先)
目标:最大化 token/s,延迟可以妥协
vLLM 配置(Qwen2.5-72B,4×H100):
bash
vllm serve Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 4 \
--max-model-len 32768 \
--gpu-memory-utilization 0.92 \
--max-num-seqs 256 \
--max-num-batched-tokens 16384 \
--optimization-level 2
SGLang 配置:
bash
python3 -m sglang.launch_server \
--model-path Qwen/Qwen2.5-72B-Instruct \
--tp-size 4 \
--context-length 32768 \
--mem-fraction-static 0.90 \
--max-running-requests 4096 \
--chunked-prefill-size 16384 \
--cuda-graph-max-bs 512 \
--schedule-conservativeness 0.3
场景 C:DeepSeek-V3/R1 生产部署
目标:在 8×H200 上跑起来且不 OOM
bash
# SGLang(DeepSeek 官方推荐引擎)
python3 -m sglang.launch_server \
--model-path deepseek-ai/DeepSeek-R1 \
--tp 8 \
--trust-remote-code \
--enable-dp-attention \
--dp-size 8 \
--mem-fraction-static 0.85 \
--cuda-graph-max-bs 512 \
--max-running-requests 256 \
--chunked-prefill-size 8192 \
--context-length 32768 \
--enable-flashinfer-mla
# vLLM(备选,V1 引擎)
vllm serve deepseek-ai/DeepSeek-R1 \
--tensor-parallel-size 8 \
--max-model-len 32768 \
--gpu-memory-utilization 0.80 \
--max-num-seqs 16 \
--max-num-batched-tokens 8192 \
--enable-expert-parallel
六、调参方法论:四步走
第一步:跑通基准
先用保守参数把模型跑起来,记录基线吞吐:
bash
# vLLM 压测
python3 -m vllm.benchmarks.serve \
--model your-model \
--dataset-name random \
--random-input-len 1024 \
--random-output-len 256 \
--num-prompts 500
# SGLang 压测
python3 -m sglang.bench_serving \
--backend sglang \
--dataset-name random \
--random-input 1024 \
--random-output 256 \
--num-prompts 500 \
--host 127.0.0.1 --port 30000
第二步:最大化 KV Cache
逐步提高 --gpu-memory-utilization / --mem-fraction-static,每次 +0.02,压测一轮,直到出现 OOM 再回退 0.02。这是投入产出比最高的单步操作。
第三步:扩大 CUDA Graph 覆盖
把 --cuda-graph-max-bs 从默认翻倍(如 256→512),同时将显存分配参数下调 0.02-0.03(因为 CUDA Graph 缓冲区吃显存)。对比吞吐变化。
第四步:场景化微调
根据你的场景选型:
- 在线服务 → 关注 P95 延迟,降低
max-num-seqs/max-running-requests - 离线批处理 → 关注 token/s,提高并发上限 + 激进调度(SGLang 降低 conservativeness)
- 长上下文 → 设实际
max-model-len,降低chunked-prefill-size
七、常见踩坑汇总
| 坑 | 现象 | 修复 |
|---|---|---|
| V1 默认 max-num-seqs=256 | warmup OOM | 降到 32-64 |
| max-model-len 用理论最大值 | KV Cache 极小、频繁 preemption | 设为实际业务需求值 |
| CUDA Graph 没覆盖实际批量 | 日志 cuda graph: False,吞吐偏低 |
提高 --cuda-graph-max-bs |
| SGLang schedule-conservativeness 默认值 | KV Cache 利用率 < 0.9 且排队多 | 降到 0.3 |
| DeepSeek 没开 DP Attention | 每卡存一份完整 KV Cache,显存浪费 | 加 --enable-dp-attention --dp-size 8 |
| 多 socket 服务器跨 NUMA | GPU 间通信延迟高 | vLLM 加 --numa-bind |
| CPU 核心不够(<2+N) | GPU 利用率低 | vLLM 至少 2+N 物理核心(N=GPU 数) |
| 开了 speculative decoding 但没配参数 | 启动失败 | SGLang 必须同时配 --speculative-draft |
八、总结
调参的本质是显存在四个池子之间做权衡。优先级从高到低:
- 设对
max-model-len/context-length------这是最容易白捡的显存 - 调高显存分配比例------从默认值往上探,找到 OOM 临界点
- 扩大 CUDA Graph 覆盖------从默认 256 提到 512/768
- 场景化微调并发和调度------在线降并发、离线提并发、SGLang 调 conservativeness
- 按需加加速选项------FP8 量化、torch.compile、speculative decoding
记住:不换硬件、不动模型、只改启动参数,吞吐量翻 3-5 倍是完全可行的。 上面的 CUDA Graph 基准就是证据:DeepSeek-V3 从 39 token/s 到 285 token/s,靠的只是几个 flag。