vLLM:GPU集群上的推理引擎,多用户并发才是它的主场
你一个人跑大模型,llama.cpp 足够了——轻量、快、CPU都能凑合。但当你的 API 要同时服务 50 个人、100 个人,甚至像我们 ai.godsun.pro 做多模型路由中转站那样,7×24 小时不间断接请求,事情就不一样了。单用户场景下的”够用”,在并发面前会变成灾难。
vLLM 就是专门解决这个问题的。它不是给你本地聊天用的,它是给 GPU 集群跑生产级推理服务用的。GitHub 上 83000+ 的 Star 说明了它的江湖地位。
1. vLLM:当你的 AI 服务要给多人用
先说结论:如果你只是自己跑模型玩,vLLM 大材小用;如果你要把模型当服务对外提供,vLLM 几乎是开源方案里唯一正确的选择。
为什么?因为传统推理框架在并发场景下有两个致命问题:
第一,KV Cache 内存浪费严重。 每个请求在 GPU 里要预分配一块连续内存存放 Key-Value 缓存,大小按最大序列长度算。一个 Llama-3-70B 模型,每个 token 的 KV 缓存大约 160KB(80 层 × 8 KV 头 × 128 维 × 2 字节),一条 2048 token 的请求就要预分配约 327MB。但实际生成可能只用了一半——剩下的全是浪费。PagedAttention 论文里的实测数据:60-80% 的预分配 KV 内存是空的。
第二,静态批次让 GPU 干等。 传统做法是凑一批请求一起跑,等最长的那个生成完了才能接下一批。短请求早就结束了,它的 GPU 槽位就在那空着等。混合长度负载下,GPU 利用率可能跌到 20-40%。
这两个问题叠加在一起:内存浪费限制了并发数,静态批次又让有限并发下的 GPU 算力闲置。vLLM 用两个核心技术同时解决了它们。
2. PagedAttention 为什么快
PagedAttention 是 vLLM 的灵魂,思路来自操作系统的虚拟内存管理。
操作系统怎么做内存管理?
程序要内存,操作系统不直接给它一大块连续物理内存,而是通过页表映射:程序看到的是虚拟地址,实际物理页可以分散在内存各处,按需分配,用多少给多少。
PagedAttention 用同样的思路管 KV Cache
每个请求不再预分配一整块连续显存,而是维护一张逻辑块表,映射到物理上不连续的 KV 块。每个物理块存放 16 个 token 的 KV 张量(默认 block_size=16),生成了新 token 才分配新块。
这样的好处是显而易见的:
- 内存浪费从 60-80% 降到约 4%。 只有每个序列最后一个未填满的块会浪费最多 15 个 token 位,而不是整个预分配空间。
- 按需分配,用完即还。 请求结束了,它的物理块立刻回到空闲池,下一个请求马上能用。
- Copy-on-Write 支持并行采样。 beam search 或
best_of场景下,fork 出来的序列共享父序列的 KV 块,只在产生分歧时才分配新块,零拷贝开销。
当然有代价:非连续块需要自定义 CUDA 内核通过块表做 gather 操作,在 batch size=1 时这个开销反而比连续的 FlashAttention 慢一点。但并发越高,内存节省带来的收益越大,gather 的相对开销可以忽略。
vLLM 底层根据 GPU 型号自动选择 FlashAttention-2 或 FlashAttention-3 内核,同时预捕获 CUDA Graph 减少内核启动开销,把推理延迟压到更低。
Continuous Batching:不让 GPU 闲着
光解决内存碎片还不够,还得解决”等最慢请求”的问题。Continuous Batching(也叫 iteration-level scheduling)的做法是:每完成一次 forward pass,就检查有没有请求结束了。结束的请求立刻释放资源,等待队列里的新请求立刻补进来。
vLLM 的调度器维护三个队列:
- Waiting:还没开始 prefill 的请求
- Running:正在 decode 的请求
- Swapped:KV 块被驱逐到 CPU 内存的请求
每个 iteration,解码请求优先调度,生成一个 token 后检查是否结束。结束了就回收块、让新请求进来。实测对比静态批次,吞吐量提升 2-4 倍,尾部延迟也更稳定。
当 KV 缓存池快满了怎么办?调度器会抢占(preemption)最早进来的请求,两种模式:
- recompute(默认):直接丢弃被抢占请求的 KV 块,恢复时从头重新 prefill。零 PCIe 开销,但恢复时 GPU 要多干活。
- swap:把 KV 块搬到 CPU 内存,恢复时再搬回来。PCIe 4.0 x16 约 32GB/s 的带宽,长上下文场景下搬运可能要几百毫秒。
如果你发现 vllm:num_preemptions_total 指标持续增长,说明 GPU 显存真的不够用了——要么降 --max-model-len,要么加卡。
还有更多:Prefix Caching 和 Chunked Prefill
Prefix Caching 自动缓存共享的系统提示词前缀。多个请求如果 prompt 开头相同(比如都带了同一段 system prompt),直接复用已计算好的 KV 块,不用重新算。在高重复场景下,吞吐提升 32% 到成本降低 90% 都有可能。默认开启。
Chunked Prefill 解决超长 prompt 独占引擎的问题。一个 32K token 的长请求如果不切分,整个 engine step 都被它霸占,其他请求排队等。Chunked Prefill 把长 prefill 切成小块,和其他请求的 decode 交替执行,避免队头阻塞。
3. 部署实战
基础部署:一条命令启动 OpenAI 兼容 API
pip install vllm
# 单 GPU 启动
vllm serve Qwen/Qwen2.5-32B-Instruct
--host 0.0.0.0
--port 8000
--gpu-memory-utilization 0.9
--max-model-len 4096
启动后,你就拥有了一个和 OpenAI API 完全兼容的推理服务:
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="not-needed"
)
response = client.chat.completions.create(
model="Qwen/Qwen2.5-32B-Instruct",
messages=[{"role": "user", "content": "你好"}]
)
print(response.choices[0].message.content)
这意味着你现有的所有基于 OpenAI SDK 的代码,改一行 base_url 就能切换到自己的 vLLM 服务。对于我们做 API 中转站的场景来说,这一点至关重要——上游接口协议统一,路由逻辑零修改。
多 GPU:Tensor Parallelism
模型太大一张卡装不下?vLLM 支持张量并行,把模型切到多张 GPU 上:
vllm serve Qwen/Qwen2.5-72B-Instruct
--tensor-parallel-size 4
--gpu-memory-utilization 0.9
4 张 A100 80GB 跑 72B 模型,BF16 精度刚好。如果显存紧张,量化来帮忙。
量化:用更少显存跑更大模型
vLLM 支持多种量化方案,这里给一个实用的选择指南:
| 量化方式 | 精度损失 | 推理速度 | 适用场景 |
|---|---|---|---|
| FP8 | 极小 | 几乎无损,可能更快 | H100/H200 等 Hopper+ 架构,首选方案 |
| AWQ (INT4) | 小 | 有反量化开销,但省显存 | 显存受限场景,70B 模型塞进单卡 |
| GPTQ (INT4) | 小 | 与 AWQ 相当 | 和 AWQ 二选一,看哪个有现成的量化模型 |
| GGUF | 取决于量化等级 | 在 vLLM 上性能不佳 | 不推荐在 vLLM 中使用,那是 llama.cpp 的格式 |
# FP8 量化模型
vllm serve meta-llama/Llama-3.1-70B-Instruct-FP8
--tensor-parallel-size 2
# AWQ 量化模型
vllm serve Qwen/Qwen2.5-72B-Instruct-AWQ
--tensor-parallel-size 2
实测数据:FP8 在 Hopper 架构上推理质量几乎与 BF16 无异,是生产部署的甜点选择。AWQ/GPTQ 在 INT4 下能让 70B 模型用 35-40GB 显存跑起来,代价是反量化的一点计算开销。
Speculative Decoding:用小模型猜,大模型验
vLLM 还支持投机解码——用一个小的 draft model 先猜几个 token,大模型一次验证多个 token,猜对的直接接受,猜错的从错误位置重新生成。
vllm serve Qwen/Qwen2.5-72B-Instruct
--speculative-model Qwen/Qwen2.5-0.5B
--num-speculative-tokens 5
--tensor-parallel-size 4
在 batch size 较小、序列不太长的场景下,单请求延迟可以降低 1.5-2 倍。但注意:高并发场景下投机解码的收益会下降,因为 GPU 本来就很忙,draft model 的计算也在抢资源。
Docker 部署(推荐生产环境)
docker run --runtime nvidia --gpus all
-v ~/.cache/huggingface:/root/.cache/huggingface
-p 8000:8000
vllm/vllm-openai:latest
--model Qwen/Qwen2.5-32B-Instruct
--gpu-memory-utilization 0.9
--max-model-len 4096
加上 --enable-prefix-caching、--disable-log-requests 等参数,生产环境就基本可用了。
4. 与 llama.cpp 的定位差异
这可能是最常被问到的问题,直接说结论:
| 维度 | vLLM | llama.cpp |
|---|---|---|
| 核心场景 | 多用户并发生产服务 | 单用户本地推理 |
| 硬件要求 | 必须 NVIDIA GPU | CPU/GPU/Mac 都行 |
| 并发能力 | 数百用户无压力 | 5 人以上就开始崩 |
| 部署复杂度 | Docker + GPU 驱动 | 一个二进制文件 |
| 内存管理 | PagedAttention,~4% 浪费 | 传统预分配,灵活但碎片多 |
| 量化格式 | GPTQ/AWQ/FP8 | GGUF(生态最全) |
| API 兼容 | 原生 OpenAI 兼容 | 需要第三方套壳 |
| 多 GPU | Tensor Parallelism 原生支持 | 有限支持 |
| 启动速度 | 慢(要预热 CUDA Graph) | 快 |
llama.cpp 的优势是极致的通用性:没有 GPU?CPU 照跑。Mac 上 M 系列芯片优化得很好。GGUF 量化格式选择丰富,从 Q2_K 到 Q8_0,各种精度和体积的平衡。一个人用,它体验非常好。
但一旦你要对外提供 API 服务,llama.cpp 的问题就来了:它本质上是个推理库,不是服务框架。并发请求的处理很原始,没有 Continuous Batching,没有 PagedAttention,KV 缓存管理粗放。有人实测,5 个并发用户时 Ollama(基于 llama.cpp)就开始响应延迟飙升,而 vLLM 在同样硬件上跑 50 个并发还稳如老狗。
所以选择很简单:
- 自己用、本地开发、没有 NVIDIA GPU → llama.cpp / Ollama
- 对外提供 API 服务、多用户并发 → vLLM
这不是谁更好的问题,是定位不同。就像 Nginx 和 Python 的 http.server 都能跑 Web 服务,但你不会拿 http.server 上生产。
5. 什么场景选 vLLM
适合 vLLM 的场景
-
API 中转站 / AI 平台:像我们 ai.godsun.pro 这样的多模型路由中转服务,需要 7×24 稳定运行、多用户并发、OpenAI 兼容接口,vLLM 是自然选择。
-
企业内部 AI 服务:几十到几百人的团队共用一个模型服务,请求有高峰有低谷,vLLM 的 Continuous Batching 能自动适应当前负载。
-
RAG / Agent 应用后端:多个 Agent 同时调用 LLM,请求间有大量共享前缀(system prompt),Prefix Caching 直接帮你省掉重复计算。
-
GPU 集群推理:多卡、多节点的生产部署,vLLM 的 Tensor Parallelism 和分布式支持直接可用。
不适合 vLLM 的场景
-
没有 NVIDIA GPU:vLLM 依赖 CUDA,AMD GPU 支持有限,CPU 推理不是它的目标。没有 GPU 就别想了。
-
个人本地使用:一个人用的话,vLLM 的 PagedAttention 和 Continuous Batching 优势发挥不出来,反而启动慢、占用资源多。llama.cpp / Ollama 更合适。
-
极致低延迟单请求:batch size=1 时,PagedAttention 的 gather 开销反而让单次推理比裸 FlashAttention 慢一点点。如果你只关心单个请求的首 token 延迟,而且永远只有一个请求,vLLM 不是最优解。
-
资源极度受限的边缘设备:树莓派、小内存 VPS——这些根本不是 vLLM 的目标平台。
一个实用的决策流程
你有 NVIDIA GPU 吗?
├─ 没有 → llama.cpp / Ollama
└─ 有 → 同时服务几个人?
├─ 1-3 人,偶尔用 → llama.cpp / Ollama
└─ 4 人以上,或 7×24 服务 → vLLM
写在最后
vLLM 不是万能的,但在”GPU 上的多用户并发推理”这个赛道上,它目前没有真正的对手。PagedAttention 解决了内存碎片,Continuous Batching 解决了 GPU 闲置,OpenAI 兼容 API 解决了接入成本——这三个问题恰好是生产环境最痛的。
83000+ Star、Meta 和 Mistral AI 在用、Apache 2.0 开源——如果你正在搭建自己的 AI 推理服务,vLLM 值得认真投入。
by 数码罗记·godsun.pro