vLLM:GPU集群上的推理引擎,多用户并发才是它的主场

vLLM:GPU集群上的推理引擎,多用户并发才是它的主场

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 的调度器维护三个队列:

  1. Waiting:还没开始 prefill 的请求
  2. Running:正在 decode 的请求
  3. 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 的场景

  1. API 中转站 / AI 平台:像我们 ai.godsun.pro 这样的多模型路由中转服务,需要 7×24 稳定运行、多用户并发、OpenAI 兼容接口,vLLM 是自然选择。

  2. 企业内部 AI 服务:几十到几百人的团队共用一个模型服务,请求有高峰有低谷,vLLM 的 Continuous Batching 能自动适应当前负载。

  3. RAG / Agent 应用后端:多个 Agent 同时调用 LLM,请求间有大量共享前缀(system prompt),Prefix Caching 直接帮你省掉重复计算。

  4. GPU 集群推理:多卡、多节点的生产部署,vLLM 的 Tensor Parallelism 和分布式支持直接可用。

不适合 vLLM 的场景

  1. 没有 NVIDIA GPU:vLLM 依赖 CUDA,AMD GPU 支持有限,CPU 推理不是它的目标。没有 GPU 就别想了。

  2. 个人本地使用:一个人用的话,vLLM 的 PagedAttention 和 Continuous Batching 优势发挥不出来,反而启动慢、占用资源多。llama.cpp / Ollama 更合适。

  3. 极致低延迟单请求:batch size=1 时,PagedAttention 的 gather 开销反而让单次推理比裸 FlashAttention 慢一点点。如果你只关心单个请求的首 token 延迟,而且永远只有一个请求,vLLM 不是最优解。

  4. 资源极度受限的边缘设备:树莓派、小内存 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

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注