vLLM 高性能推理部署:大模型服务化从入门到上线 — 千级并发、毫秒级响应的完整方案
大模型 demo 跑出来了,老板说"把它部署上线"。然后你发现每秒只能处理 3 个请求,延迟 8 秒——这就是很多人从「跑通模型」到「生产上线」最难受的一道坎。
vLLM 是当前解决这个问题的首选方案。它把 Qwen2.5-7B 的推理吞吐从 3 req/s 拉到 50+ req/s——还不需要改模型一行代码。
这篇文章用一套完整的部署链路——模型启动、API 封装、Docker 打包、压测验证——带你从零到上线。

1. vLLM 到底做了什么
传统的 Transformer 推理有几处严重的浪费:
- 显存碎片化:每个请求分配固定大小的 KV Cache,不同请求长度不同导致大量空闲
- 串行批处理:等一个 batch 里最长的那个请求算完,短请求的 GPU 计算单元一直在空转
- 内存拷贝:每次 forward 都在 CPU/GPU 之间搬数据
vLLM 的核心改进——PagedAttention——把 KV Cache 按「页」管理(类似操作系统虚拟内存)。空闲页被回收分配给新请求,显存利用率从 30% 拉到 90%+。
直观对比:同一张 A100,跑 Qwen2.5-7B:
| 方案 | 吞吐 (req/s) | 延迟 P50 | 延迟 P99 | 显存占用 |
|---|---|---|---|---|
| HuggingFace 原生 | 3.2 | 2.1s | 8.3s | 18 GB |
| vLLM (默认) | 28.7 | 0.4s | 1.8s | 16 GB |
| vLLM (prefix caching) | 52.3 | 0.2s | 0.9s | 14 GB |
2. 安装与环境
# vLLM 需要 CUDA 11.8+,推荐在 Linux 上安装
pip install vllm
# 可选:FlashInfer 后端(比默认 FlashAttention 更快)
pip install flashinfer -i https://flashinfer.ai/whl/cu124
验证安装:
from vllm import LLM
# 快速测试
llm = LLM(model="Qwen/Qwen2.5-1.5B-Instruct")
outputs = llm.generate(["用一句话介绍北京"])
print(outputs[0].outputs[0].text)
3. 离线批量推理
先看最简单的——不用起服务,直接批量跑推理。
# batch_inference.py — 离线批量推理
from vllm import LLM, SamplingParams
# ── 模型加载 ──
llm = LLM(
model="Qwen/Qwen2.5-7B-Instruct",
dtype="float16", # 推理用 fp16 足够
max_model_len=4096, # 限制最大长度以节省显存
gpu_memory_utilization=0.90, # 显存利用率(留一点给系统)
tensor_parallel_size=1, # 单卡为 1,多卡设为 GPU 数量
trust_remote_code=True,
enforce_eager=False, # False = 使用 CUDA Graph 加速
)
# ── 采样参数 ──
sampling_params = SamplingParams(
temperature=0.7,
top_p=0.9,
max_tokens=512,
stop=["<|im_end|>", "<|endoftext|>"],
repetition_penalty=1.05,
)
# ── 批量推理 ──
prompts = [
"<|im_start|>user\n解释一下什么是RESTful API<|im_end|>\n<|im_start|>assistant\n",
"<|im_start|>user\n写一段Python快速排序<|im_end|>\n<|im_start|>assistant\n",
"<|im_start|>user\n什么是Docker容器化<|im_end|>\n<|im_start|>assistant\n",
]
outputs = llm.generate(prompts, sampling_params)
for prompt, output in zip(prompts, outputs):
generated = output.outputs[0].text
token_count = len(output.outputs[0].token_ids)
print(f"生成长度: {token_count} tokens")
print(f"内容: {generated[:200]}...\n")
4. OpenAI 兼容 API 服务
生产环境的核心需求:HTTP 接口、流式输出、多客户端并发。vLLM 自带 OpenAI 兼容服务器。
# 启动 OpenAI 兼容 API 服务
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-7B-Instruct \
--dtype float16 \
--max-model-len 4096 \
--gpu-memory-utilization 0.90 \
--port 8000 \
--host 0.0.0.0 \
--enable-prefix-caching \
--max-num-seqs 256 \
--max-num-batched-tokens 8192
关键参数: - --enable-prefix-caching:缓存系统 prompt 的 KV Cache,多轮对话场景大幅提速 - --max-num-seqs:同时处理的最大请求数(并行度上限) - --max-num-batched-tokens:单次 forward 的最大 token 数
客户端调用——和 OpenAI SDK 完全兼容:
# client.py — 用 OpenAI SDK 调 vLLM
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="not-needed", # vLLM 不需要 API key
)
# 普通对话
response = client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=[
{"role": "system", "content": "你是 AI 部署专家"},
{"role": "user", "content": "解释 vLLM 的 PagedAttention 原理"},
],
temperature=0.7,
max_tokens=512,
)
print(response.choices[0].message.content)
# 流式输出
stream = client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=[{"role": "user", "content": "写一首关于AI的诗"}],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
5. FastAPI 服务封装
生产环境通常还要加一层自己的 FastAPI 服务——鉴权、限流、日志、prompt 模板管理、结果缓存。

# api_server.py — FastAPI 生产级封装
from fastapi import FastAPI, HTTPException, Depends
from fastapi.responses import StreamingResponse
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from openai import AsyncOpenAI
import asyncio
import time
import logging
app = FastAPI(title="vLLM Chat API", version="1.0.0")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
vllm_client = AsyncOpenAI(base_url="http://localhost:8000/v1", api_key="not-needed")
logger = logging.getLogger("vllm_api")
# ── 请求模型 ──
class ChatRequest(BaseModel):
messages: list[dict] = Field(..., description="对话消息列表")
temperature: float = Field(0.7, ge=0.0, le=2.0)
max_tokens: int = Field(512, ge=1, le=4096)
stream: bool = Field(False)
class ChatResponse(BaseModel):
content: str
model: str
tokens_used: int
time_elapsed: float
# ── 简易 token 鉴权 ──
async def verify_token(x_api_key: str | None = None):
# 生产环境换 JWT 或 OAuth2
if x_api_key and x_api_key == "your-secret-token":
return True
# raise HTTPException(401, "Invalid token")
return True # 示例中放行
# ── 非流式接口 ──
@app.post("/v1/chat", response_model=ChatResponse)
async def chat(req: ChatRequest, _=Depends(verify_token)):
t0 = time.time()
try:
response = await vllm_client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=req.messages,
temperature=req.temperature,
max_tokens=req.max_tokens,
timeout=30,
)
except asyncio.TimeoutError:
raise HTTPException(504, "模型推理超时")
except Exception as e:
logger.error(f"vLLM error: {e}")
raise HTTPException(500, f"推理服务异常: {e}")
elapsed = time.time() - t0
choice = response.choices[0]
logger.info(f"chat done: {choice.finish_reason}, tokens={response.usage.total_tokens}, time={elapsed:.2f}s")
return ChatResponse(
content=choice.message.content,
model=response.model,
tokens_used=response.usage.total_tokens,
time_elapsed=round(elapsed, 2),
)
# ── 流式接口 ──
@app.post("/v1/chat/stream")
async def chat_stream(req: ChatRequest, _=Depends(verify_token)):
async def event_generator():
try:
stream = await vllm_client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=req.messages,
temperature=req.temperature,
max_tokens=req.max_tokens,
stream=True,
)
async for chunk in stream:
if chunk.choices[0].delta.content:
yield f"data: {chunk.choices[0].delta.content}\n\n"
yield "data: [DONE]\n\n"
except Exception as e:
yield f"data: [ERROR] {e}\n\n"
return StreamingResponse(event_generator(), media_type="text/event-stream")
# 启动: uvicorn api_server:app --host 0.0.0.0 --port 8080
6. Docker 容器化部署
# Dockerfile
FROM nvidia/cuda:12.4.0-runtime-ubuntu22.04
RUN apt-get update && apt-get install -y python3.11 python3-pip && \
ln -s /usr/bin/python3.11 /usr/bin/python
WORKDIR /app
RUN pip install vllm fastapi uvicorn openai -i https://pypi.tuna.tsinghua.edu.cn/simple
COPY api_server.py .
# 预下载模型(构建时下载,避免启动等待)
RUN huggingface-cli download Qwen/Qwen2.5-7B-Instruct --local-dir /models/Qwen2.5-7B
EXPOSE 8080
CMD ["sh", "-c", "python -m vllm.entrypoints.openai.api_server \
--model /models/Qwen2.5-7B \
--port 8000 --host 0.0.0.0 & \
uvicorn api_server:app --host 0.0.0.0 --port 8080"]
# docker-compose.yml
version: "3.8"
services:
vllm-server:
build: .
ports:
- "8080:8080"
environment:
- CUDA_VISIBLE_DEVICES=0
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
volumes:
- ./models:/models
restart: unless-stopped
# 构建 & 启动
docker compose build
docker compose up -d
7. 压力测试
# 用 vegeta 做压测
echo 'POST http://localhost:8080/v1/chat' | \
vegeta attack -body test_payload.json -rate=50/s -duration=60s | \
vegeta report
# 典型输出(A100,Qwen2.5-7B,prefix caching 开启):
# Requests [total, rate, throughput] 3000, 50.00, 48.72
# Latencies [mean, 50, 95, 99, max] 412ms, 389ms, 621ms, 1.1s, 2.4s
# Success Rate [ratio] 100.00%
// test_payload.json
{
"messages": [
{"role": "user", "content": "简述微服务和单体架构的区别"}
],
"temperature": 0.7,
"max_tokens": 256
}
8. 生产 Checklist
上线前对照这份清单逐项确认:
□ GPU 驱动 >= 525.60.13(nvidia-smi 确认)
□ CUDA >= 11.8(nvcc --version 确认)
□ vLLM >= 0.6.0(pip show vllm 确认)
□ gpu_memory_utilization 设为 0.85-0.90(留余量给 CUDA context)
□ 开启 --enable-prefix-caching(多轮对话场景必须)
□ 配置 systemd supervisor 自动重启(vLLM 偶有 CUDA OOM 崩溃)
□ 加 health check endpoint(GET /health → {"status": "ok"})
□ 接入 Prometheus metrics(vLLM 自带 /metrics)
□ 单 GPU 故障时自动切换(如果有双卡,用 nginx upstream 做 failover)
踩坑记录
- Docker 里 CUDA 版本要对齐 — 宿主机
nvidia-smi显示的 CUDA 版本和 Docker 镜像的cuda:x.x.x-runtime必须一致。不一致的话启动时直接 Segmentation Fault。 max_model_len设太大反而慢 — 每个请求都会预留这个长度的 KV Cache 空间。如果你实际对话不超过 2048 token,设 4096 就是在浪费显存。- 内存泄漏 — vLLM 0.5.x 以前有已知的内存泄漏 bug(issue #4712),长时运行显存缓慢增长。0.6.0 以上基本修了,但生产环境建议每周凌晨自动重启。
金句
"大模型部署不是把模型跑起来就完了——是从 3 req/s 到 50 req/s 的工程化跨越。"
如果你也在做模型部署,或者遇到了延迟/吞吐/显存的问题,评论区说说你的模型大小和 GPU 配置——我帮你算算预期吞吐。
更多推荐
所有评论(0)