news 2026/5/17 7:52:27

vLLM 高性能推理部署:大模型服务化从入门到上线 — 千级并发、毫秒级响应的完整方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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.22.1s8.3s18 GB
vLLM (默认)28.70.4s1.8s16 GB
vLLM (prefix caching)52.30.2s0.9s14 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)

踩坑记录

  1. Docker 里 CUDA 版本要对齐— 宿主机nvidia-smi显示的 CUDA 版本和 Docker 镜像的cuda:x.x.x-runtime必须一致。不一致的话启动时直接 Segmentation Fault。
  2. max_model_len设太大反而慢— 每个请求都会预留这个长度的 KV Cache 空间。如果你实际对话不超过 2048 token,设 4096 就是在浪费显存。
  3. 内存泄漏— vLLM 0.5.x 以前有已知的内存泄漏 bug(issue #4712),长时运行显存缓慢增长。0.6.0 以上基本修了,但生产环境建议每周凌晨自动重启。

金句

"大模型部署不是把模型跑起来就完了——是从 3 req/s 到 50 req/s 的工程化跨越。"


如果你也在做模型部署,或者遇到了延迟/吞吐/显存的问题,评论区说说你的模型大小和 GPU 配置——我帮你算算预期吞吐。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/17 7:52:26

Uber JVM Profiler:分布式系统性能剖析利器实战指南

1. 项目概述&#xff1a;一个面向分布式系统的JVM性能剖析利器如果你在维护一个由成百上千个微服务组成的分布式系统&#xff0c;并且正在为定位性能瓶颈而头疼——比如某个API的响应时间在特定时段突然飙升&#xff0c;或者某个服务的CPU使用率居高不下&#xff0c;但你却无法…

作者头像 李华
网站建设 2026/5/17 7:49:30

autoshow:从终端录制到交互式动画,打造高质量命令行演示

1. 项目概述&#xff1a;一个面向开发者的自动化演示工具最近在折腾一个内部技术分享会&#xff0c;需要把几个命令行工具的操作流程录制成动态演示。一开始想着用录屏软件搞定&#xff0c;但发现效果很死板&#xff0c;没法突出重点&#xff0c;后期加注释也麻烦。后来在GitHu…

作者头像 李华
网站建设 2026/5/17 7:47:19

JetBrains IDE 30天试用重置:一键解决方案的完整实践指南

JetBrains IDE 30天试用重置&#xff1a;一键解决方案的完整实践指南 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter 当您正专注于代码调试时&#xff0c;IDE突然弹出"评估期已结束"的红色警告&#xf…

作者头像 李华
网站建设 2026/5/17 7:46:27

终极指南:3步实现PotPlayer实时字幕翻译,外语视频无障碍观看

终极指南&#xff1a;3步实现PotPlayer实时字幕翻译&#xff0c;外语视频无障碍观看 【免费下载链接】PotPlayer_Subtitle_Translate_Baidu PotPlayer 字幕在线翻译插件 - 百度平台 项目地址: https://gitcode.com/gh_mirrors/po/PotPlayer_Subtitle_Translate_Baidu 还…

作者头像 李华
网站建设 2026/5/17 7:46:18

基于Plan 9与Lua的9router:构建统一命名空间的网络服务框架

1. 项目概述与核心价值最近在折腾家庭网络和边缘计算设备时&#xff0c;我偶然发现了一个名为decolua/9router的开源项目。这个名字乍一看有点神秘&#xff0c;“9router”听起来像是一个路由器固件或者网络工具&#xff0c;而“decolua”这个前缀又暗示了它与Lua脚本语言的深度…

作者头像 李华
网站建设 2026/5/17 7:44:55

FinalMesh(三维模型查看器)

链接&#xff1a;https://pan.quark.cn/s/efaa710d91f7FinalMesh是一款好用的三维模型图像查看工具&#xff0c;支持主流的文件格式&#xff0c;可以一键三维文件进行查看操作&#xff0c;除此之外&#xff0c;软件还提供共了人性化的编辑功能&#xff0c;包括物体移动&#xf…

作者头像 李华