4. 性能调优
这是什么:性能调优 = 找出服务卡在哪,把显存、并发和精度这三块拧到合适的档位。
为什么用:上一章服务起来了,可一压测就露馅:显存爆掉、吞吐上不去、延迟忽高忽低。参数调不好,再贵的显卡也是白买。
如何用:本章先算清显存的账,再调批处理和前缀缓存,最后用 vllm bench serve 量一量到底快了多少。
4.1 先算一笔显存账
显存被两样东西吃掉:
- 模型权重 —— 参数量 × 每参数字节数。8B 模型按 FP16 算约 16 GB。
- KV cache —— 上下文缓存,随并发数和长度一起涨。
vLLM 启动时会先探测一遍显存,然后在日志里告诉你能装多少:
INFO [gpu_model_runner.py] GPU KV cache size: 190,080 tokens
INFO [gpu_model_runner.py] Maximum concurrency for 40,960 tokens per request: 4.64x
第二行的意思是:假设每个请求都占满 40960 个 token,显存里能同时塞 4.64 个这样的请求。这个数字偏低,说明上下文开太大或权重太大,得动手调。
4.2 显存三板斧
| 参数 | 调大的后果 | 调小的后果 |
|---|---|---|
--gpu-memory-utilization |
抢更多显存,KV cache 更足 | 别的进程没显存用,甚至 OOM |
--max-model-len |
能接更长的上下文 | 并发数下降,长请求会被拒 |
--kv-cache-dtype fp8 |
KV cache 减半 | 精度略降 |
--gpu-memory-utilization 默认是 0.92(vLLM 0.32.0 的实际默认值),也就是这台卡九成多都归它。同一张卡上要跑两个实例,就得自己分一分:
vllm serve Qwen/Qwen3-8B --gpu-memory-utilization 0.45 --port 8001
--kv-cache-dtype fp8 是性价比很高的一招:KV cache 存成 8 位浮点,容量直接翻倍,吞吐跟着涨。
vllm serve Qwen/Qwen3-8B --kv-cache-dtype fp8
4.3 批处理与并发
| 参数 | 含义 | 调大的后果 |
|---|---|---|
--max-num-seqs |
一批里最多同时处理几条序列 | 并发上限高,但每条占的显存多 |
--max-num-batched-tokens |
一轮最多处理多少 token | 单次算得更多,吞吐更高,显存峰值更高 |
vLLM 的 V1 引擎默认 --max-num-seqs 128、--max-num-batched-tokens 2048,而 --enable-chunked-prefill 默认开着——长 prompt 会被切块,不会一个人霸占整轮计算。
想提高吞吐,可以先把每轮预算提上去:
vllm serve Qwen/Qwen3-8B --max-num-batched-tokens 8192 --max-num-seqs 256
4.4 前缀缓存
如果你的请求都带同一段 system prompt 或同一份长文档,开了前缀缓存就不用每次重算。vLLM V1 引擎默认已经开启,写上 --enable-prefix-caching 只是更保险。
看命中率:
curl -s http://localhost:8000/metrics | grep prefix_cache
你会看到(示意):
vllm:prefix_cache_queries_total{model_name="Qwen/Qwen3-8B"} 1024.0
vllm:prefix_cache_hits_total{model_name="Qwen/Qwen3-8B"} 896.0
命中率高说明 prompt 复用度好,收益大;命中率低就先把 prompt 结构改改。
4.5 量化:用精度换显存
量化 = 把权重压成更少的比特,显存省下来,模型就能塞进更小的卡。
vLLM 支持的主流方式:FP8(W8A8)、AWQ(INT4)、GPTQ(INT4)、bitsandbytes 等。
两种用法:
# 方式一:起一个已经量化好的模型仓库(最省事)
vllm serve <HF 上已量化的模型名>
# 方式二:显式指定量化后端
vllm serve Qwen/Qwen3-8B --quantization awq
你会看到(示意):
INFO [config.py:1234] Quantization config: awq
INFO [gpu_model_runner.py:2412] GPU KV cache size: 413,696 tokens
FP8 需要 Ampere 及以上(RTX 30 系、L4、A100、H100 等),老卡只能走 INT4 那条路。
4.6 拿数据说话
别凭感觉调,跑个基准:
vllm bench serve --backend vllm --model Qwen/Qwen3-8B \
--host localhost --port 8000 \
--num-prompts 100 --request-rate inf
你会看到(示意):
============ Serving Benchmark ============
Backend: vllm
Maximum request concurrency: 128
Successful requests: 100
Benchmark duration: 12.34 s
Request throughput: 8.10 requests/s
Output token throughput: 1024.00 tokens/s
重点看两个数:Request throughput(每秒处理多少请求)和 Output token throughput(每秒吐多少字)。调参前后各跑一次,让数字说话。
动手改
- 记下默认参数下的
GPU KV cache size,再把--max-model-len从 40960 改成 8192,看看这个数变成多少 - 加上
--kv-cache-dtype fp8,对比 KV cache 容量和吞吐的变化 - 用
vllm bench serve跑一次基线,再把--max-num-batched-tokens调到 8192 跑第二次,把两组数字记下来
小结
- 显存 = 权重 + KV cache,先看启动日志里的
GPU KV cache size --gpu-memory-utilization默认 0.92,同卡多实例要手动分--max-model-len调小能换来更高的并发数--kv-cache-dtype fp8让 KV cache 容量翻倍- 量化(FP8 / AWQ / GPTQ)是模型塞进小卡的主要手段
- 调完必须用
vllm bench serve验证,别只看感觉
下一章:部署与运维 🐸