从零搭建 vLLM 推理服务:部署 Qwen 的完整流程

82 阅读5分钟

一、vLLM 简介

1.1 什么是 vLLM?

vLLM 是目前业界最流行的高性能开源大模型推理框架。它不是用于“训练”模型的平台,而是专门用于“运行”已经训练好的大模型(如 GPT、Llama、Qwen 等)的加速引擎。

1.2 核心特性

定位 :解决大模型部署阶段显存占用高、吞吐量低、响应慢的问题。

性能 :在同等硬件条件下,vLLM 的吞吐量通常比传统的 Hugging Face Transformers 库高 2 到 24 倍。

1.3 核心技术

PagedAttention(核心创新)

image-20260212214248443

  • 痛点:传统 Attention 机制会预分配显存,导致大量碎片浪费(显存利用率通常低于 40%)。
  • 方案:借鉴操作系统的“虚拟内存分页”技术,将 KV Cache 切分成小块(Page/Block),按需动态分配。这使得显存利用率可提升至 90% 以上

连续批处理(Continuous Batching)

image-20260212214338756

  • 痛点:传统 Batching 必须等待一个 Batch 中最长的请求生成完毕,导致 GPU 出现空闲等待。
  • 方案:实现细粒度的动态调度,一旦某个请求生成结束,立即插入新请求,保持 GPU 始终处于满载计算状态。

二、环境准备

2.1 硬件要求

  • GPU:NVIDIA GPU(推荐 A100/A10/4090/3090)。

    • 显存提示:部署 Qwen2.5-7B-Instruct (bfloat16) 建议显存 ≥24GB
  • CPU/内存:建议 16GB+ 系统内存。

2.2 软件要求

  • 操作系统:Linux (Ubuntu 20.04/22.04 推荐)。

  • Python:3.9 - 3.12。

  • CUDA关键点,推荐 CUDA 12.1 或 11.8。

    • 检查命令:nvcc --version

2.3 创建虚拟环境

conda create -n vllm python=3.10 -y
conda activate vllm

三、vLLM 安装

3.1 安装方式

# 安装 vLLM 稳定版 (会自动适配 CUDA 12.1 或 11.8)
pip install vllm
​
# 验证安装
python -c "import vllm; print(f'vLLM version: {vllm.__version__}')"

4.1 下载 Qwen 模型(推荐 SDK 方式)

修正点:直接 git clone 大文件极易失败且不支持断点续传。推荐使用 ModelScope SDK 下载。

  1. 安装下载工具

    pip install modelscope
    
  2. 执行下载脚本 创建一个 python 脚本 download_model.py

    from modelscope import snapshot_download
    ​
    # 下载 Qwen2.5-7B-Instruct 到当前目录的 models 文件夹下
    model_dir = snapshot_download(
        'qwen/Qwen2.5-7B-Instruct', 
        cache_dir='./models', 
        revision='master'
    )
    print(f"模型已下载至: {model_dir}")
    
  3. 运行下载

    python download_model.py
    

五、服务部署

5.1 启动 vLLM 服务

假设模型下载路径为 ./models/qwen/Qwen2.5-7B-Instruct

vllm serve ./models/qwen/Qwen2.5-7B-Instruct \
  --host 0.0.0.0 \
  --port 8000 \
  --tensor-parallel-size 1 \
  --dtype bfloat16 \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.95 \
  --trust-remote-code

5.2 关键参数详解

  • --tensor-parallel-size 1:单卡设为 1;如果是双卡 4090 跑 7B 模型,依然设为 1(单卡足够),跑 72B 模型则设为 2 或 4。
  • --max-model-len 8192重要。Qwen2.5 支持 32k+,但在 24GB 显存下,设置过大会导致 OOM(显存溢出)。8192 是一个安全值,如果显存充足可尝试 16384。
  • --gpu-memory-utilization 0.95:允许 vLLM 使用 95% 的 GPU 显存(预留 5% 给系统开销)。
  • --trust-remote-code:部分新模型架构需要此参数信任执行代码。

六、部署后测试

image-20260212214059581

6.1 基础连通性测试

# 健康检查
curl http://localhost:8000/health

6.2 OpenAI 兼容接口测试

vLLM 原生兼容 OpenAI API 格式,可直接调用:

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "./models/qwen/Qwen2.5-7B-Instruct",
    "messages": [
      {"role": "system", "content": "你是一个专业的AI助手。"},
      {"role": "user", "content": "请解释一下什么是微服务架构?"}
    ],
    "temperature": 0.7,
    "max_tokens": 512
  }'

(注意:model 字段需要填写启动服务时指定的模型路径名称,或者通过 curl http://localhost:8000/v1/models 查询准确名称)

image-20260212214132356

6.3 压力与性能测试脚本

修正点:优化了并发统计逻辑,确保 P95 数据具有统计意义。

创建 benchmark.py

import time
import threading
import numpy as np
from openai import OpenAI
​
# 配置
BASE_URL = "http://localhost:8000/v1"
API_KEY = "EMPTY"
MODEL_NAME = "./models/qwen/Qwen2.5-7B-Instruct" # 请确认与 v1/models 返回一致
CONCURRENT_REQUESTS = 20  # 并发数
TOTAL_TOKENS = 256        # 生成长度client = OpenAI(base_url=BASE_URL, api_key=API_KEY)
​
def send_request(results):
    start_time = time.time()
    try:
        client.chat.completions.create(
            model=MODEL_NAME,
            messages=[{"role": "user", "content": "请写一段关于人工智能未来的200字短文。"}],
            max_tokens=TOTAL_TOKENS,
            temperature=0.8
        )
        latency = time.time() - start_time
        results.append(latency)
        print(f"请求完成: {latency:.2f}s")
    except Exception as e:
        print(f"请求失败: {e}")
​
def run_benchmark():
    threads = []
    results = []
    
    print(f"开始压测:并发数 {CONCURRENT_REQUESTS}...")
    
    for _ in range(CONCURRENT_REQUESTS):
        t = threading.Thread(target=send_request, args=(results,))
        threads.append(t)
        t.start()
        
    for t in threads:
        t.join()
        
    if results:
        avg = np.mean(results)
        p95 = np.percentile(results, 95)
        print(f"\n=== 测试结果 ===")
        print(f"成功请求: {len(results)}")
        print(f"平均延迟: {avg:.2f}s")
        print(f"P95 延迟: {p95:.2f}s")
        print(f"预估吞吐量 (QPS): {len(results) / max(results):.2f}")
​
if __name__ == "__main__":
    run_benchmark()

七、监控与进阶优化

7.1 监控指标

vLLM 暴露了 Prometheus 格式的监控指标。

  • Endpoint: http://localhost:8000/metrics

  • 关键指标

    • vllm:num_requests_running:当前正在处理的请求数。
    • vllm:gpu_cache_usage_perc:KV Cache 显存使用率(接近 100% 说明负载饱和)。

7.2 生产环境优化建议

  1. 启用量化(Quantization)

    • 显存不足时,推荐使用 AWQGPTQ 量化模型(如 Qwen2.5-7B-Instruct-AWQ)。
    • 显存占用可减少约 50%,吞吐量提升显著。
    • 启动命令增加:--quantization awq
  2. KV Cache 优化

    • 如果输入文本极长(如文档分析),适当增加 --gpu-memory-utilization 至 0.98(需谨慎,防 OOM)。
    • 如果并发极高,适当减小 --max-model-len 以腾出显存给 Batch Size。

八、Docker 部署方案(推荐)

使用 Docker 可以避免 CUDA 版本冲突。

8.1 编写 docker-compose.yml

version: '3.8'
services:
  vllm:
    image: vllm/vllm-openai:latest
    container_name: vllm-service
    runtime: nvidia
    environment:
      - HUGGING_FACE_HUB_TOKEN=your_token_if_needed
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
    volumes:
      # 映射宿主机模型目录到容器内的 /models
      - ./models/qwen/Qwen2.5-7B-Instruct:/models/qwen:ro
    # 显式指定容器内模型路径
    command: >
      --model /models/qwen
      --host 0.0.0.0
      --port 8000
      --dtype bfloat16
      --gpu-memory-utilization 0.95
      --max-model-len 8192
    ports:
      - "8000:8000"
    ipc: host  # 必须配置,共享内存,防止多进程通信失败
    restart: unless-stopped

8.2 启动与验证

docker-compose up -d
docker logs -f vllm-service

当看到日志输出 Uvicorn running on http://0.0.0.0:8000 时,即代表启动成功。


九、总结

通过 vLLM 部署 Qwen2.5 模型,我们实现了“高吞吐、低延迟”的推理服务。对于技术团队而言,重点关注以下三点以保证线上稳定性:

  1. 显存管理:合理设置 max-model-lengpu-memory-utilization 避免 OOM。
  2. 版本匹配:确保 CUDA、PyTorch 和 vLLM 版本兼容。
  3. 量化策略:资源受限时,优先选择 AWQ/GPTQ 量化模型而非硬抗 FP16。