上一篇用Docker部署推理服务时提到了vLLM,但只是一笔带过。这篇文章深入聊聊vLLM的部署和调优——这是目前吞吐量最高的开源推理框架,没有之一。
PagedAttention:vLLM快的秘密
传统推理框架处理KV Cache时,会在显存中预分配连续的大块内存。问题是:不同请求的序列长度不同,预分配的大小按最大长度来,实际利用率经常不到50%。显存就这么被浪费了;
vLLM的PagedAttention借鉴了操作系统的虚拟内存分页思想:把KV Cache分成固定大小的"页面",按需分配,用完回收。效果是显存利用率大幅提升,同一块显卡能同时处理更多请求;
实际测试数据:在A100 80GB上跑Qwen2.5-7B,HuggingFace Transformers大约20 tokens/s/vLLM达到80+ tokens/s——4倍差距。
安装
pip install vllm
# 验证CUDA可用
python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name())"
启动推理服务
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-7B-Instruct \
--host 0.0.0.0 \
--port 8000 \
--max-model-len 8192 \
--gpu-memory-utilization 0.9
首次启动会下载模型(如果本地没有的话),加载时间几分钟到十几分钟不等。看到Uvicorn running的消息就表示服务就绪了。
核心参数详解
gpu-memory-utilization控制显存使用比例。0.9表示用90%的显存。设太高可能OOM,设太低浪费显存。建议从0.9开始,遇到OOM就降到0.85;
max-model-len最大上下文长度。设太大占用更多显存。根据实际需求设,不需要128K上下文就别设128K;
tensor-parallel-size多卡张量并行。4卡A100就设4,vLLM会自动把模型拆分到4张卡上;
dtype数据类型。auto自动选择(通常选bfloat16如果硬件支持)。bfloat16精度和float16差不多,但数值稳定性更好;
多卡部署72B模型
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 4 \
--max-model-len 4096 \
--gpu-memory-utilization 0.9
4张A100 80GB可以流畅运行72B模型。注意多卡通信需要NVLink或高速PCIe,不然通信开销会拖慢整体速度。
量化部署
AWQ或GPTQ量化可以把显存需求减半:
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-7B-Instruct-AWQ \
--quantization awq \
--max-model-len 8192
量化后的模型大约节省50%显存,推理速度提升20-30%,精度损失在大多数场景下可以忽略。
投机解码
用小模型快速生成候选token,大模型批量验证。在合适的负载下显著提升生成速度:
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-7B-Instruct \
--speculative-model Qwen/Qwen2.5-1.5B-Instruct \
--num-speculative-tokens 5
监控
vLLM内置Prometheus端点(/metrics),暴露的关键指标包括:vllm:avg_generation_throughput_toks_per_s(生成吞吐量)、vllm:num_requests_running(运行中请求数)、vllm:gpu_cache_usage_perc(KV Cache使用率)、vllm:e2e_request_latency_seconds(端到端延迟)。
写在最后
vLLM把推理性能的天花板抬高了一大截。对于需要处理大量并发请求的生产环境来说,它是当前最佳选择。先用默认参数跑起来,再根据监控数据逐步调优——不要一开始就追求极致参数,稳定比极致更重要。