背景信息:使用VLLM降低首Token和后续Token生成所需时间,现有两张24G4090GPU
1. Qwen3-30B-A3B-Instruct-2507-FP8模型释义
- 该模型是MoE架构,FP8也就是8位浮点数精度;
- A3B表示Active 3 Billion,这表示:
- 虽然它总参数有30B,但每次处理一个字的时候,只有3B参数在干活,
- 它拥有30B模型的博学知识,但推理速度却接近3B模型的轻快,
- 4090显卡原生支持FP8加速,相比于BF16,FP8显存占用减半,计算速度翻倍,并且几乎不损失精度。
2. Docker部署前的检查
- 显卡驱动检查nvidia-smi
- 驱动版本Driver Version必须在535.104+,因为FP8精度和最新的vLLM算子需要此配置支持
- PCle带宽检查nvidia-smi -q -d UTILIZATION
- 看一下Max Link Speed 和 Current Link Speed。4090在做张量并行TP的时候,两张卡要频繁交换数据,如果主板把第二个插槽的速度降到了PCle 3.0 x4,那速度就会比预期的降低一半,确保是Gen4x16或者x8.
- 内存和Swap
- 虽然模型在显存里面,但加载模型的瞬间需要大量的内存RAM。对于30B的模型,建议内存至少64GB,否则加载的时候可能OOM
3. Dokcer 环境
vLLm有很多复杂的CUDA算子,不同版本的PyTorch和CUDA组合极易报错
-
Dockerfile或者直接拉取官方镜像
bashdocker pull vllm/vllm-openai:xxxx,指定版本,不要用latest -
启动脚本
bash#!/bin/bash # 定义路径,改造成你自己的路径 MODEL_PATH="/data/models/Qwen3-30B-A3B-Instruct-2507-FP8" CONTAINER_NAME="vllm-qwen-prod" docker run -d --gpus all \ --name $CONTAINER_NAME \ --shm-size=16gb \ --ipc=host \ -p 8000:8000 \ -v $MODEL_PATH:/model \ --restart unless-stopped \ vllm/vllm-openai:v0.7.0 \ --model /model \ --tensor-parallel-size 2 \ --max-model-len 16384 \ --gpu-memory-utilization 0.90 \ --trust-remote-code \ --dtype fp8 \ --kv-cache-dtype fp8 \ --served-model-name qwen-30b- --shm-size=16gb:Docker的共享内存,多卡并行NCCL通讯时需要,默认的64MB会直接导致死机
- --tensor-parallel-size:2:把30B的矩阵切开,分布到两张卡上
- --max-model-len:16384:4090显存只有24GB,如果不限制长度,vLLM会默认尝试申请巨大的显存空间。如果不需要超长对话,设置成16K或者8K可以显著增加吞吐量
- --kv-cache-dtype:fp8:现在用的模型就是FP8模型,把KV缓存也设置位FP8,可以多一倍的对话内容。
- --gpu-memory-utilization:0.90:预留10%的显存给显卡驱动和系统,防止爆显存。
4.启动服务
脚本运行后,盯着日志docker logs -f vllm-qwen-prod
有三个阶段:
- Weights loading(60s):有进度条,看看是否卡住,卡住了就说明磁盘IO过慢
- NCCL Initialization(10s):最容易报错的地方,如果两张卡没法通信,就会出现
NCCL Error。如果报错了,就在docker run里面增加环境变量-e NCCL_P2P_DISABLE=1 - Capturing CUDA Graphs(60-120s):VLLM启动,预算路径,GPU占用会在此时跳动
5. 测试
-
吞吐量压测(用 vLLM 自带工具):
进入容器内部,跑一个脚本,看看每分钟能处理多少请求。
-
脚本:
python
import time
from openai import OpenAI
client = OpenAI(api_key="EMPTY", base_url="http://localhost:8000/v1")
def test_inference():
start = time.perf_counter()
response = client.chat.completions.create(
model="qwen-30b",
messages=[{"role": "user", "content": "请详细解释一下量子纠缠。"}],
stream=True
)
print("Tokens: ", end="")
first_token_time = None
for chunk in response:
if chunk.choices[0].delta.content:
if first_token_time is None:
first_token_time = time.perf_counter() - start
print(chunk.choices[0].delta.content, end="", flush=True)
end = time.perf_counter()
print(f"\n\n--- 性能指标 ---")
print(f"首 Token 延迟 (TTFT): {first_token_time:.3f} s")
print(f"总耗时: {end - start:.3f} s")
test_inference()
6. 可能存在的问题
问题 1:启动报错 Out of Memory (OOM)
原因:4090 显存 24G 扣掉系统占用可能只剩 22G。两张卡 44G 左右。30B 的 FP8 模型占 30GB,剩下的显存不够放 max-model-len 设定的缓存。
解决方法:减小 --max-model-len 到 8192,或者降低 --gpu-memory-utilization 到 0.85。
问题 2:首 token 还是慢,为什么?
原因 :Prompt 太长 :Qwen 预处理长文本需要时间。CPU 瓶颈:vLLM 虽然是 GPU 计算,但调度靠 CPU。如果你的 CPU 是 E5 系列那种老古董,调度会变慢。
验证:看看日志里的 PreFill 时间。
问题 3:模型胡言乱语
原因:Qwen3 可能需要特定的 Chat Template。
解决方法:在调用接口时,确保使用标准的 OpenAI 格式,vLLM 会自动调用模型文件夹里的 tokenizer_config.json 来处理格式。