🐸 青蛙编程网
首页 / AI / 推理服务 vLLM / 4. 性能调优

4. 性能调优

这是什么:性能调优 = 找出服务卡在哪,把显存、并发和精度这三块拧到合适的档位。

为什么用:上一章服务起来了,可一压测就露馅:显存爆掉、吞吐上不去、延迟忽高忽低。参数调不好,再贵的显卡也是白买。

如何用:本章先算清显存的账,再调批处理和前缀缓存,最后用 vllm bench serve 量一量到底快了多少。

4.1 先算一笔显存账

显存被两样东西吃掉:

  1. 模型权重 —— 参数量 × 每参数字节数。8B 模型按 FP16 算约 16 GB。
  2. 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(每秒吐多少字)。调参前后各跑一次,让数字说话。

动手改

  1. 记下默认参数下的 GPU KV cache size,再把 --max-model-len 从 40960 改成 8192,看看这个数变成多少
  2. 加上 --kv-cache-dtype fp8,对比 KV cache 容量和吞吐的变化
  3. 用 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 验证,别只看感觉

下一章:部署与运维 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。