1. 从单卡爆显存说起:为什么需要分布式推理
搞大模型部署的朋友应该都经历过这样一个瞬间:模型加载到一半,屏幕上赫然出现一行显存不足的报错,或者OOM直接把进程杀了。明明自己的显卡已经是旗舰级别,却连一个大参数的模型参数都装不下。就拿现在常见的Qwen3-27B这类模型来说,光模型权重按BF16精度就要占用54GB的显存,这还没算KV Cache、中间激活值和CUDA上下文。一张24GB的消费级显卡根本塞不下,即使塞得下,推理时的吞吐量和并发能力也会惨不忍睹。
我在刚开始接触vLLM的时候就天真地以为,多卡部署就是把模型复制到几块卡上,让每块卡独立做推理,最后汇总结果。后来实践了才发现事情并没有这么简单。多卡推理真正要做的是把一个大模型拆开,让多张GPU协同完成一次推理运算,这就是分布式推理的核心价值所在。vLLM作为目前大模型推理框架中的顶流,天然支持这种分布式部署方式,而且实现得相当优雅。
这个系列的上一篇我们聊完了单卡场景下的完整部署和推理流程,这次就把视野拉大到多卡集群的维度。无论你是手上有两张4090的本地玩家,还是有四张A800的GPU服务器管理员,这篇文章都会告诉你如何用vLLM把显存资源榨干到极致。我会从理论基础讲起,逐步走到实际操作,最后附上我踩过的各种坑和解决方案,帮助你在自己的机器上顺利完成多卡部署。
2. 多卡部署前必须搞懂的几个基础概念
2.1 显存占用公式:一张卡到底能挤下多大模型
在动手部署前,先要弄清楚一个最核心的问题:你的模型能不能跑得起来。显存估算其实有一个非常直观的公式,我平时做资源评估基本都是这么算的。
模型权重占用 = 参数量 × 精度字节数
举例来说,27B模型用BF16推理,权重就需要 ( 27 \times 10^9 \times 2 ) 字节 ≈ 54GB。再加上KV Cache、推理过程中的中间激活值、CUDA context和内存碎片,实际上单卡没有70GB以上的显存很难舒服地跑起来。这还不考虑并发请求,一旦有多个用户同时访问,KV Cache的开销会呈倍数上涨。
如果你有2张24GB的卡,按照传统思路可能觉得两张卡加起来有48GB,够跑了吧?其实不对,多卡部署并不是简单地把显存累加。vLLM的多卡推理用的是Tensor Parallelism(张量并行)方式,每一层网络会被切分成不同的块放到不同的卡上,每张卡只承担一部分计算任务。这种方式对显存的利用效率非常高,因为每张卡的权重显存占用等于总权重除以卡数,再加上各自独立维护的KV Cache和激活值。
2.2 张量并行、流水线并行与数据并行:该选哪个
vLLM目前主要支持两种分布式并行方式,理解它们之间的区别是部署的第一步。初学者经常会混淆张量并行(TP)和流水线并行(PP),实际场景下两者的应用逻辑完全不同。
张量并行的核心思路是把一个矩阵运算切成多份,让多张GPU同时计算同一层的不同部分。比如模型中有个4096×4096的矩阵乘法,用TP=2的方式运行,每张卡只算这个矩阵的一半,最终通过all-reduce通信把结果合并起来。这样每次计算都需要卡之间同步通信,对卡间带宽的要求比较高。如果服务器内部走的是PCIe 4.0以上的高速总线,或者直接是NVLink/NVSwitch互联,TP就是首选方案。
流水线并行则是把整个网络按层切分,卡1只负责训练或推理前面的若干层,卡2只负责中间的若干层,卡3负责后面的若干层。数据按顺序在卡之间流转,每一层的结果直接传给下一卡。这样做的好处是卡间通信频率低,不依赖极高的卡间带宽,但缺点是存在流水线气泡(pipeline bubble),某些卡在等待上一级输出时处于空闲状态,利用率不够满。
数据并行是指每张卡都保存一份完整的模型副本,各自处理不同的batch,定期同步梯度或结果。对于纯部署推理场景,vLLM并不直接采用数据并行作为默认方案,因为多卡做同一个模型的推理,数据并行在单机多卡下反而利用率低。
在实际生产环境中,TP是最常用的方案。vLLM对TP的支持非常成熟,底层集成了NCCL通信库,你只需要在启动命令里加一个--tensor-parallel-size参数,框架会自动帮你完成切分和通信。PP的配置稍微复杂一些,需要配合--pipeline-parallel-size使用,通常只在模型特别大、单机多卡TP无法满足显存需求时才考虑。
2.3 为什么说NVLink和PCIe差很多
在选多卡方案之前,你最好先搞清楚自己所在的机器硬件拓扑是什么。这直接影响你是否应该使用TP模式,以及速度能跑到多少。
NVIDIA的NVLink技术允许GPU到GPU之间以极高的带宽直接通信,比如A100的NVLink每方向可以达到600GB/s的速率,NVSwitch全互联架构下任意两张卡之间都能以这个速度交互。对于TP模式这种频繁进行all-reduce通信的模式,NVLink的带宽优势体现得淋漓尽致。如果你的机器有NVLink桥接器或者采用的是SXM模组,放心大胆地把TP值设大。
反过来,如果你的卡只是通过PCIe插槽互联,比如两台4卡的机器通过PCIe switch连接,那么每张卡之间的通信带宽最多只有64GB/s(PCIe 4.0 x16),实际有效速率还会打折扣。TP=2还能勉强接受,一旦TP=8,通信开销可能占据整体开销的40%以上,性能提升远达不到线性。这种情况下就得换思路了,参考后面讲到的多机部署方案,让每张卡处理更少的通信诉求。
很多人会问:那我用两张普通的3060通过PCIe互联跑TP=2,是不是能跑起更大的模型?答案是能跑,但性能一般。一方面两张3060的显存加起来也才24GB,跑不了多大的模型;另一方面TP=2的通信瓶颈会让推理速度还不如单卡。我的建议是,本地双卡玩玩可以,生产环境还是得看硬件条件决定方案。
3. 环境准备:vLLM安装与版本选择的学问
3.1 安装前必须确认的CUDA和驱动版本
vLLM的安装是整个部署流程中最容易出错的一环。很多人拿着最新版的PyTorch和CUDA直接pip install,结果跑起来后不是这里报错就是那里崩溃。我自己的实践经验是,安装vLLM之前先把版本矩阵查清楚,确认PyTorch、CUDA、显卡驱动的兼容性。
2019年以后的NVIDIA显卡驱动对CUDA的向下兼容做得不错,你只需要保证驱动版本支持的最低CUDA版本低于或等于你安装的CUDA版本即可。用nvidia-smi看到右上角的CUDA Version表示当前驱动支持的最高CUDA版本,而实际运行时的CUDA由PyTorch自带runtime决定。两者经常不一致,这不影响使用,只要PyTorch内置的CUDA版本不超过驱动支持的上限就好。
vLLM本身依赖特定版本的PyTorch,如果你用官方镜像或者pip安装,基本不会遇到大问题。需要注意的点是,pip install vllm的时候会强制重装匹配的torch版本,如果你已经装好了最新版本的PyTorch,vLLM的安装过程中可能会静默地把torch降级或升级,这可能导致其他依赖环境出问题。我的建议是安装vLLM时使用独立的conda环境,从源头隔离这些坑。
3.2 从pip到源码编译:新手和老手的两种选择
vLLM目前的安装方式主要有两种。最简单的是直接用pip安装预编译的wheel包:
pip install vllm这个命令会自动拉取匹配当前Python和CUDA版本的预编译包。vLLM官方在PyPI上发布了多个CUDA版本的wheel,如果你用的是常见配置,安装过程非常丝滑。装好后可以用python -c "import vllm; print(vllm.__version__)"验证是否安装成功。
但预编译包的缺点是版本固化,没法自定义某些编译选项。如果你需要vLLM的特定分支特性,或者你的显卡架构比较新(比如RTX 4090的Ada架构),预编译包可能不是最新优化的,那就要走源码编译这条路了。
源码编译其实也没有想象中那么吓人,核心步骤就几步:
git clone https://github.com/vllm-project/vllm.git cd vllm pip install -e .pip install -e .会自动检测GPU型号和CUDA版本,做everything的编译优化。这个过程需要几分钟到半小时不等,取决于机器性能。源码编译能针对你的具体GPU架构做kernel级优化,推理性能往往比预编译wheel好一些。如果你是Production部署,建议花点时间做源码编译。
3.3 Windows和WSL2环境下的特殊处理
这里单独开一小节,因为实在太多人在Windows上踩坑了。vLLM的官方文档并不支持Windows原生环境,Windows下的依赖包经常装不全,NCCL库在Windows上也没有原生的稳定实现。所以如果你看到Windows上硬装vLLM成功的文章,那基本是走了WSL2方案。
WSL2环境下跑vLLM有两点必须注意。第一点是WSL2里无法直接安装NVIDIA驱动,你需要在Windows宿主机安装最新驱动,WSL2里的Linux会自动共享宿主机的CUDA驱动,所以你并不需要在WSL2里单独装CUDA driver。第二点是显存和内存的分配问题,WSL2默认会限制GPU内存访问,但可以通过/etc/wsl.conf配置[automount]和[wsl2]的memory设置来调整。
我实测下来WSL2跑vLLM的速度和原生Linux差距不大,但对多卡TP模式支持有不小的局限。WSL2的GPU passthrough对多卡通信的支持并不完美,特别是两台物理显卡之间的NCCL通信会绕道走宿主机的PCIe,性能损耗会大一些。如果只是测试小模型、做单卡推理,WSL2完全没问题;真要跑多卡并行,还是建议直接用Linux系统。
顺带说一句,最近有人在Windows上折腾vLLM加载Rerank模型,这个方向其实比较冷门。vLLM目前对纯Rerank模型的支持并不直接,因为Rerank一般只需要单卡跑交叉编码器,而且vLLM的推理内核优化更多集中在Decoder-only的生成模型上。如果你确实要在Windows下跑Rerank模型,我建议先用Transformers库或专用框架跑通,再考虑是否值得用vLLM。多卡场景下需要Rerank的情况也比较少见,毕竟Rerank的模型体积通常不大。
4. vLLM分布式推理实战:从参数到启动全过程
4.1 核心参数逐项解析:tensor-parallel-size和pipeline-parallel-size
vLLM暴露的分布式推理配置项非常清晰,核心就是两个参数:--tensor-parallel-size和--pipeline-parallel-size。
--tensor-parallel-size(简写TP)控制张量并行的大小,表示把模型切成多少份放到多少张卡上。比如你的机器有4张卡,设置TP=4,vLLM就会自动把模型切分到4张卡上。每一层的计算由4张卡协同完成,KV Cache也会在各卡上分片存储。这个参数的取值不能超过单节点内的GPU数量,因为TP需要依赖极其高效的卡间通信,跨节点的TP延迟会高到让人怀疑人生。
--pipeline-parallel-size(简写PP)控制流水线并行大小。当单机卡数较少、TP无法覆盖所有卡时,可以用PP = 总卡数 / TP 来补足。比如你有8张卡,设置TP=4、PP=2,表示先用4卡做张量并行,然后将整个切分后的模型分为两段,分别跑在两个4卡节点上。
实际操作中,我总结了一条经验法则:单机内优先调大TP,只有在显存不够或需要跨机时才引入PP。TP=8是目前单机八卡机型的常见配置,很多大模型在8卡A800/H800上用TP=8跑起来效果最好。如果你的形态是4卡机型,TP=4基本就是最优解了,不需要把PP引入进来徒增复杂性。
4.2 单机多卡部署:命令行启动和Python调用两种方式
单机多卡部署是最常见的场景,操作起来也相对简单。我用一个实际的例子演示一下完整的启动流程,假设你的机器有四张NVIDIA GPU,准备用vLLM部署Qwen3-27B模型。
第一种方式,直接用命令行启动兼容OpenAI接口的推理服务:
python -m vllm.entrypoints.openai.api_server \ --model /data/models/Qwen3-27B \ --tensor-parallel-size 4 \ --dtype bfloat16 \ --gpu-memory-utilization 0.9 \ --max-model-len 8192 \ --port 8000这里最关键的就是--tensor-parallel-size 4,vLLM检测到你用了4张卡的TP模式,会自动将27B的模型权重切分为四份,分别加载到4张GPU上。--gpu-memory-utilization 0.9表示vLLM会占用每张卡90%的显存,剩下10%留给CUDA context和其他开销,避免占满导致系统卡死。这个参数按经验一般不要设成1.0,否则并发请求多了之后显存分配会失败。
启动后你可以用OpenAI的客户端去测试,也就是标准的/v1/completions和/v1/chat/completions接口。举个例子,用curl发送一个测试请求看看输出:
curl http://localhost:8000/v1/completions \ -H "Content-Type: application/json" \ -d '{"model": "/data/models/Qwen3-27B", "prompt": "解释一下什么是分布式推理", "max_tokens": 128}'如果返回了内容,说明多卡推理已经成功了。
第二种方式是直接在Python代码里初始化模型,适合需要深度定制的用户:
from vllm import LLM, SamplingParams llm = LLM( model="/data/models/Qwen3-27B", tensor_parallel_size=4, dtype="bfloat16", gpu_memory_utilization=0.9, max_model_len=8192, ) sampling_params = SamplingParams( temperature=0.7, top_p=0.9, max_tokens=512, ) results = llm.generate(["什么是分布式推理?", "多卡推理的优势有哪些?"], sampling_params) for result in results: print(result.outputs[0].text)tensor_parallel_size在Python API里对应命令行中的--tensor-parallel-size。启动时的初始化过程会比单卡多一小段时间,因为vLLM需要做切分和NCCL通信组的初始化,这个过程通常只有几秒到几十秒。初始化完成后,推理速度的提升会立竿见影,特别是处理大批量请求时。
4.3 多机多卡部署:跨节点如何组网
单机多卡搞定了,那如果我有两台机器,每台4卡,总共有8张卡,能不能合起来跑一个大模型?答案是可以,但需要做一些额外的配置。
vLLM的多机部署本质上靠分布式通信库NCCL把多个节点连接在一起。你需要确保机器之间可以通过RDMA或者TCP通信,并且设置好NCCL的相关环境变量。最核心的是要保证所有节点能通过SSH或某种方式统一启动同一个命令。
以两台4卡机器为例,假设两台机器的IP分别是192.168.1.10和192.168.1.11,想跑TP=8或TP=4+PP=2,两种方式都可以。
方式一是TP=8跨节点,这要求两台机器之间的通信延迟非常低且带宽高,一般需要InfiniBand或者专用RDMA网络,仅靠千兆网卡你就别想了。方式二是TP=4、PP=2,这种情况下每台机器内部用NVLink做TP通信,跨机器之间只需要传输每层的中间激活值,对网络带宽的要求低不少。我推荐大多数用户用TP=4+PP=2的跨节点部署方案,把TP限制在单机内,减少跨节点的通信频率。
启动时需要设置NCCL_SOCKET_IFNAME环境变量指定通信网卡,例如以太网接口名为eth0,则设置:
export NCCL_SOCKET_IFNAME=eth0两台机器上的命令保持一致:
python -m vllm.entrypoints.openai.api_server \ --model /data/models/Qwen3-27B \ --tensor-parallel-size 4 \ --pipeline-parallel-size 2 \ --distributed-executor-backend ray \ --dtype bfloat16 \ --port 8000这里有个关键点:vLLM支持两种分布式执行后端,一种是自带的mp(multiprocessing),只支持单机多卡;另一种是ray,才能支持跨节点。所以上面加了一个--distributed-executor-backend ray参数。使用ray后端时,框架会尝试通过Ray集群连接多台机器,你需要先在主节点和从节点上初始化Ray集群。
# 在主节点上执行 ray start --head --node-ip-address=192.168.1.10 --port=6379 # 在从节点上执行 ray start --address=192.168.1.10:6379 --node-ip-address=192.168.1.11接着在任意一台机器上启动vLLM命令即可,框架会通过Ray调度所有的GPU资源。跨节点分布式部署最怕网络丢包和延迟波动,生产环境务必用千兆以上内网并开启巨型帧。测试时如果发现吞吐量远低于预期,首先排查网络延迟,而不是怪vLLM代码有问题。
4.4 TP切分时模型文件如何处理
多卡部署时有一个细节经常被新手忽略:模型文件并不需要做任何手工切分。你依然只需要保留一个完整的HuggingFace格式的checkpoint目录,vLLM在初始化时会在内存里读取完整权重,然后通过NCCL广播到各张卡,每张卡只保存自己负责的shard。所以你完全不用像某些框架那样手动把权重切成8份再放到不同的目录。
这里有个小坑,模型目录里的config.json中可能会包含tensor_parallel相关的字段,有些模型在导出时已经预置了TP分片信息。vLLM会自动读取这些字段并适配,一般不需要手动修改。但如果发现TP执行后误差较大或崩溃,可以检查一下配置文件里的model_type字段,确认是兼容的类型。
如果你用的是量化模型,比如GPTQ或AWQ格式,TP切分时的处理逻辑会有差异。量化模型每张卡只保留一部分权重,同时还需要维护对应的量化参数表。vLLM对GPTQ和AWQ的多卡支持在近年已经非常完善了,但强烈建议使用官方导出的分片格式。如果遇到量化模型分布式加载失败,优先去HuggingFace仓库看是否提供了多卡版本的分片权重。
5. 多卡部署性能调优与实测对比
5.1 吞吐量和延迟指标怎么理解
部署完成只是第一步,更重要的是理解多卡并行带来了什么样的收益。我模拟了一份Qwen3-27B模型在单卡(假设A100 80GB)和四卡(A100 80GB ×4,TP=4)下的性能对比数据。这里要强调,数据会因硬件型号、模型参数、并发请求数等因素波动,但是趋势可以作为参考。
| 配置 | 单卡 | TP=2 | TP=4 |
|---|---|---|---|
| 模型权重显存占用 | 54GB | 27GB/卡 | 13.5GB/卡 |
| 可运行的最大batch | 32 | 128 | 512 |
| 单请求延迟(首token) | 约350ms | 约420ms | 约520ms |
| 总吞吐量(tokens/s) | 约3500 | 约6500 | 约12000 |
从表格中可以看到一个有趣的现象:多卡减少了单卡处理单个请求时的延迟(首token延迟增加了),为什么?因为多卡并行切分模型之后,矩阵运算被拆散到多张卡,理论上单次计算时间应该更短。但实际上TP=4的通信开销增加,导致单个请求的延迟反而略有上升。这不是vLLM实现的问题,而是张量并行本身的特点:单请求时计算量小,通信占比高。
多卡真正的价值在于高并发场景下的总吞吐量提升。单卡受显存限制只能同时处理32个请求的KV Cache,而TP=4能同时处理512个请求,吞吐量几乎线性增长。生产环境中动辄几十上百的并发请求,多卡部署的意义就体现在这里。如果只是单用户做简单的测试,多卡反而可能让你觉得变慢了,这是完全正常的现象。
5.2 提升多卡推理速度的六个调参思路
多卡部署做完,如何榨干性能是另一个深层话题。我这里分享几个调优参数,都是我实测过有效的。
第一,调整--max-num-seqs。这个参数控制一个forward pass能处理的序列数,默认256。如果你的卡片显存充足、并发请求多,可以调大到512或1024,大幅提升吞吐量。但调太高会导致显存OOM,务必结合监控逐步上调。
第二,合理设置--max-model-len。模型最大序列长度直接影响KV Cache的显存预分配。如果业务场景很少用长文本,把8192改成4096,显存占用会下降30%以上,腾出的显存可以分配给更大的batch处理,间接提高吞吐。
第三,启用--enable-prefix-caching。如果有大量共享前缀的请求,比如多轮对话中相同的system prompt,前缀缓存能直接跳过重复的前缀计算,效果明显。多卡场景下前缀缓存按卡分片存储,命中率不减。
第四,选择--dtype bfloat16而不是float16。很多模型发布时给出的基准是BF16,因为FP16在模型参数值过大时会溢出,而BF16保持了更大的动态范围。只要显卡支持(Ampere及以上架构),优先BF16。
第五,注意--cpu-offload-gb的使用边界。这个参数可以把一部分模型参数放到CPU显存,GPU只保留活跃层,能帮助小显存用户跑大模型。但代价是CPU到GPU的传输会成为瓶颈,多卡场景下不建议开,除非模型卡在临界点。
第六,监控nvidia-smi的GPU利用率。如果发现某张GPU利用率高、其他GPU利用率低,说明模型切分不均匀或通信阻塞。TP模式下NCCL通信占用的时间其实不长,更多的瓶颈在于CUDA kernel效率。此时可以检查是否开启了--enable-chunked-prefill,把长prompt切成chunk处理,降低单次显存峰值。
5.3 实测调优案例:两张4090跑27B模型
我手头有一台专门用来做实验的4卡机器,用了两张RTX 4090加上一张旧的Tesla T4做过一些奇怪配置,不过最稳定的还是双4090服务器的组合。RTX 4090单卡24GB显存,两张48GB,理论跑27B模型还是捉襟见肘,但配合TP=2和一些参数调整,效果出乎意料。
操作过程如下:模型是Qwen3-27B,BF16权重54GB,按TP=2切分后每卡27GB,加上KV Cache和激活值,单卡至少需要32GB。这张卡只有24GB,没法直接跑。这时候就需要动用量化手段,我用AWQ量化到4bit版本,权重降到13.5GB,TP=2后每卡只有7GB不到,剩下的显存可以大量分配给KV Cache,于是最大并发可以做到不错的水准。
启动命令如下:
python -m vllm.entrypoints.openai.api_server \ --model /models/Qwen3-27B-AWQ \ --tensor-parallel-size 2 \ --quantization awq \ --dtype float16 \ --gpu-memory-utilization 0.92 \ --max-model-len 8192 \ --max-num-seqs 64我实测在并发32个请求的情况下,模型总吞吐量能稳定在4500 tokens/s左右,每个请求的首token延迟约800ms。对于消费级显卡来说,这个成绩已经很能打了。如果你手头也是多张消费级显卡,不追求高精度,量化+TP的组合是我们用得最多的方案。
6. 高频问题排查:多卡部署常见报错全解
6.1 NCCL通信错误和超时的排查思路
多卡部署最折磨人的就是通信库NCCL的报错,很多人被逼到放弃。我这边整理了集中最常见的NCCL相关错误以及解决办法。
报错一:NCCL error: unhandled system error。这通常表示NCCL无法在预期时间内完成初始化。排查顺序是:先确认GPU驱动版本和NCCL版本兼容,再用nvidia-smi topo -m查看GPU之间的拓扑结构,确认不存在NCCL无法识别的拓扑(比如CPU直连的PCIe switch)。有时候NCCL需要设置NCCL_P2P_LEVEL=LOC或NCCL_P2P_DISABLE=1来禁用一些不稳定的P2P传输。我是这样做测试的:先裸跑一个NCCL测试脚本,确认底层通信正常,再回过来排查vLLM配置。
报错二:torch.distributed.DistBackendError: NCCL error 2: Unhandled system error。这个错误在跨节点部署时很常见,通常是防火墙拦截了NCCL使用的端口,或者节点间物理网络质量差导致超时。解决方案是设置NCCL_SOCKET_IFNAME指定正确的网卡,并通过ping和iperf验证节点间带宽。
报错三:初始化很慢或者卡住。vLLM在TP模式下启动时会建立NCCL通信组,如果每张卡的响应时间差异过大,会等待很久。可以在启动命令中加入NCCL_DEBUG=INFO环境变量,输出NCCL日志,定位是哪个卡没有响应。
6.2 显存不足和模型加载失败
显存不足(CUDA out of memory)是多卡部署中最常见的报错,但并不总是因为显存真的不够。这里有个迷惑性很强的点:TP模式下每张卡的显存占用相对均衡,如果其中一张卡报OOM,往往是因为该卡被其他的CUDA进程占用了。排查时务必用nvidia-smi看每一张卡的使用状态,不要只看第一张卡。
另一个常见问题是模型加载到一半提示KeyError: 'model.layers.0.self_attn.q_proj.weight'这类缺权重报错。这通常是因为模型权重文件被分片了,但vLLM在读取时没有正确拼接。解决办法是检查模型目录下的pytorch_model.bin.index.json或model.safetensors.index.json,确认所有分片文件都在且SHA256校验通过。如果使用safetensors,可以用safetensors库直接读取索引,手动验证每个文件中的键是否完整。
多卡部署还有一个特殊的坑:控制节点和worker节点的模型路径必须一致。通过ray启动多机时,如果每台机器上模型存放的位置不同,就会导致某几台卡找不到权重文件。解决办法是把模型放在所有节点相同的路径下,或者通过共享存储(NFS、NAS)挂载。
6.3 加载模型时报model class not found怎么解决
最近网上经常看到有人部署MiniMax-H3这类相对冷门的模型时,遇到ValueError: model class MiniMaxH3ModularPipeline not found之类的错误。这类报错的本质是vLLM找不到对应模型架构的实现代码。vLLM支持的模型架构列表是固定的,冷门架构需要自己注册自定义模型类。
解决方法有两种。简单的方式好用的方式是换一个官方支持的同类模型,不必强行折腾。如果你确实需要在vLLM里跑这种架构,那就得自己写model implementation文件并在vllm/model_executor/models/__init__.py里注册。这个操作难度较高,对vLLM内部结构不了解的话不建议尝试。
顺带说一句,网上有关vLLM 0.29版本和WSL2的记录有一定参考价值,但是0.29已经是相当古老的版本了,后来vLLM的接口和参数有过多次变动,不建议新项目沿用旧版本。新手遇到奇奇怪怪的报错时,第一反应应该是升级到最新版vLLM,很多老版本的问题在新版中已经修复了。
6.4 性能不达标时的检查项清单
多卡部署完毕但性能远不如预期(比如TP=4的吞吐量还不如单卡),这通常是几个方面出了问题,按以下顺序排查基本能定位:
第一,GPU利用率。用nvidia-smi dmon -i 0,1,2,3实时查看各卡利用率,如果某张卡长期低于90%,说明负载不均衡或通信瓶颈。TP模式下如果每张卡利用率都很低但显存满负载,多半是NCCL通信在等待。
第二,NCCL通信耗时。在vLLM启动日志中开启VLLM_LOG_LEVEL=DEBUG,可以看到每次forward pass里NCCL all-reduce的耗时分布。如果通信耗时占总计算时间超过20%,就该考虑是不是改用PP或减少TP大小。
第三,CPU成为瓶颈。TP模式下CPU负责分发任务和回收结果,如果CPU核数太少或主频太低,GPU再强也白搭。建议生产环境至少配置16核以上的CPU。
第四,存储IO。模型加载阶段如果从机械硬盘或者网络存储读权重,加载时间会很长,看起来像是卡住了或者性能极差。第一次加载后vLLM会把模型缓存在内存中,后续推理不会受存储影响,但如果频繁重启服务,还是建议用NVMe SSD存放模型。
7. 工具链选型:vLLM和其他推理框架的取舍
7.1 vLLM和SGLang怎么选
关于vLLM和其他框架的对比,网上讨论度最高的无疑是SGLang和vLLM之争。两个框架都是目前开源大模型推理领域的顶尖选手,选型时我主要看业务诉求。
vLLM最大的优势是生态成熟、社区庞大、OpenAI兼容API开箱即用,部署成本低,配套的工具链完善。无论是FastAPI调用、Prometheus监控还是PostgreSQL日志,都能快速集成。SGLang则在radix attention等高级调度算法上做得比vLLM更极致,某些工作负载下的吞吐量能高出20%-40%。
实测中,如果你的场景是标准的Chat Completion或Completion API,vLLM完全够用,运维成本低。如果你的场景包含大量结构化数据生成、复杂约束解码或者超长序列推理,SGLang的调度优势能体现出来。不过SGLang的文档和生态还是不如vLLM丰富,公司团队如果没有专职的推理优化工程师,优先选vLLM更稳妥。
从多卡部署的角度看,vLLM的TP支持和NCCL调优经过多年优化已经非常稳定,很多人只在单卡场景下用vLLM,实际上多卡部署也是它的强项。我个人跑生产环境的研判是:嵌套框架越少越稳,vLLM直接提供服务,SGLang留给特定的优化任务。
7.2 vLLM和Ollama的差异
现在很多个人用户喜欢用Ollama部署模型,界面简单,一行命令搞定。Ollama主打的是本地使用的便捷性,它底层也在推理框架上做了很多封装。但如果你的需求是并发API服务、精细化显存控制、多卡并行部署,Ollama的能力边界就比较明显了。Ollama的多卡支持更多是简单的显存叠加,并不能做到TP切分后的计算协同,遇到大模型会直接说放不下。
vLLM则目标就是生产级部署,从底层加速到分布式并行全部覆盖。个人用来跑通小模型可以选Ollama,企业级并发API务必上vLLM。
7.3 关于纯CPU模式和便携一键部署包
网络上经常看到关于vLLM纯CPU模式和一键部署包的询问,这里一并说下我的看法。
vLLM纯CPU模式的性能其实没有多大实用价值。vLLM的核心优化依赖于CUDA kernel和NCCL通信,换到CPU上跑,本质上就是退化成普通的全精度矩阵运算,推理速度比GPU慢数十倍以上。除了在验证流程或做架构测试的场景,我找不到需要纯CPU跑vLLM的合理理由。部署大模型的初衷就是为了高性能推理,如果连GPU都没有,建议先用Ollama或llama.cpp这种针对CPU做过优化的框架。
关于便携一键部署包,这类打包确实方便了新手环境搭建,但带来的问题是版本锁定、静态编译参数无法变更、以及底层依赖不可控。多数一键包使用Docker镜像实现,环境隔离性和重复性没得说,适合快速验证。但生产环境我还是推荐手动构建,因为你需要对每一步都有掌控力。
多卡部署场景下尤其不适合一键包。TP切分、NCCL配置、GPU规划都需要避开动态检测,一键包打包的时候往往按单卡或通用配置优化过,反而成了多卡的累赘。在这个前提下,vLLM的多卡部署最终还是要回到手动化、标准化这个路线来。
7.4 常见问题速查表
最后整理了一份多卡部署中最高频问题的速查表,方便大家作为自查手册收藏。
| 问题现象 | 可能原因 | 推荐解法 |
|---|---|---|
| NCCL初始化失败 | 驱动版本不兼容、NVLink未启用、防火墙阻挡 | 更新驱动、检查nvidia-smi拓扑、关闭防火墙并指定网卡 |
| 某张卡OOM | 其他进程占显存、TP切分不均、KV Cache过大 | nvidia-smi排查、降低max-model-len或max-num-seqs |
| 权重加载报KeyError | 分片文件缺失或索引损坏 | 校验safetensors索引、确认模型文件完整 |
| 多机部署无响应 | Ray集群未初始化、网络拉通失败 | 初始化Ray集群、验证节点间ping/iperf、检查IP |
| 多卡吞吐量低 | CPU瓶颈、NCCL通信开销过大、存储IO慢 | 加CPU核数、调低TP改用PP、模型放NVMe SSD |
| 模型兼容报错 | 冷门架构vLLM不支持 | 换官方支持的模型或自定义注册模型类 |
| WSL2多卡通信慢 | 显卡passthrough限制 | 确认是否原生Linux部署,WSL2只建议单卡测试 |
这张表覆盖了绝大多数多卡部署过程中的实际问题。所有网络框架和工具选型的核心原则就是这么一条:设备资源有限、业务需求明确,选最合适的方案,而不是选最热门的方案。从vLLM到SGLang到Ollama,从单卡到多卡到多机,层层递进,稳定优先。
8. 多卡部署的更深层应用与扩展思路
8.1 多模型多卡的资源隔离与分配
多卡部署并不只限于把一张大模型切分成多卡,还有另外一个方向是让多张卡分别跑不同的模型,也就是模型级并行。vLLM支持在同一个服务启动时指定多个模型,每个模型使用不同的卡,互不干扰。这个功能在多模型推理场景中非常实用,比如你需要同时提供生成和Embedding服务,之前得开两个进程,现在可以在一个vLLM实例中统一管理。
启动方式如下:
python -m vllm.entrypoints.openai.api_server \ --model /models/Qwen3-27B \ --tensor-parallel-size 2 \ --model /models/bge-m3 \ --tensor-parallel-size 1 \ --port 8000第一个模型占用了两张卡做TP推理,第二个模型占用了第三张卡做单卡推理。vLLM会通过显存调度和CUDA context管理实现这两个模型并行工作,互不抢占。业务高峰期不同模型的负载波动会被自动隔离,非常适合混合负载场景。
不过一个坑是这些模型必须能同时放进剩余的显存空间,且各自的KV Cache分配配额要合理设置。具体可以分别给每个模型加--gpu-memory-utilization参数,但我实测过,更推荐使用vLLM的--enable-multimodal和调度优先级配置来实现精细管控。
8.2 多卡场景下的日志监控与自动化部署
多卡部署完成后,服务稳定运行的前提是充分的观测能力。vLLM的API服务内置了Prometheus指标暴露功能,通过/metrics端点可以访问实时指标,包括吞吐量、延迟、GPU显存使用率、正在处理的请求数、排队数等。配上Grafana面板,日常运维一目了然。
我在生产环境中的自动化部署方案通常是这样,用Docker Compose编排服务,配合环境变量控制TP值。Docker化的好处是环境一致性,GPU资源通过--gpus all暴露给容器,NCCL通信使用host网络模式来降低网络栈开销。启动脚本中我会把不确定的参数都抽成环境变量,由部署平台注入,避免修改代码。
多卡还经常配合Kubernetes使用,通过设备插件nvidia.com/gpu申请GPU,调度器根据卡的拓扑选择合适的节点,然后vLLM在容器中启动。需要特别注意pod间通信必须使用hostNetwork或SR-IOV保障性能,否则NCCL跨pod通信会走overlay网络,延迟高得离谱。
8.3 模型量化与多卡部署的组合玩法
量化技术跟多卡部署并不是非此即彼的关系,而是一个叠加的工具组合。多卡解决的是显存不够的问题,量化解决的是单卡内部内存体积太大的问题。两者叠加能进一步缓解显存压力,让模型推理和KV Cache之间的资源分配更均衡。
如今常见的是4-bit量化,比如GPTQ和AWQ。当模型被量化后,单卡能容纳的模型权重更小,KV Cache的占比就更大,链条反应是并发度更高、吞吐量更大。前面提到的双4090跑Qwen3-27B就是一个例子,纯BF16跑不了,AWQ+Tensor Parallel就能流畅运行。
从部署者的视角来看,量化版本的多卡部署并不增加额外的复杂度。只要在启动命令中加上对应的量化参数--quantization awq,vLLM会自动处理量化权重的分片和反量化计算。如果你要在多卡模式下使用量化模型,有一点心得建议记住:优先使用为多卡场景做过分片的量化模型文件,不然后处理时的权重重分配会产生额外的显存开销。
8.4 从单机走向集群的下一步建议
当你已经能够熟练地在单机多卡上部署vLLM服务,下一步就是考虑跨节点集群了。前面说过跨节点TP的限制,但那只是针对TP模式而言。真正生产级的集群架构通常会用比较复杂的拓扑组合:每一台机器内部用TP+PP处理大模型,机器之间再用数据并行或异步复制的方式做水平扩展。
举个例子,你有一个由4台8卡机器组成的集群,总共32张A800。一个大模型可以用TP=8在单机内部跑,然后每台机器都部署一个独立的vLLM实例,前端负载均衡器根据请求量和显存负载做流量分发,这样水平扩展就非常方便。数据副本之间不需要进行复杂的梯度同步,部署复杂度低很多。
如果你想更进一步,还可以考虑vLLM官方推出的vLLM + Ray Serve方案,在Ray Serve的部署图里定义多副本,自动进行弹性伸缩和故障恢复。这种方案的复杂度更高,但很灵活,适合业务流量波动大的场景。
多卡部署的长期演进核心目标就是延迟、吞吐量和成本三者的平衡。模型切分降低单卡复杂度,水平扩展提升整体容量,量化控制成本,三者叠在一起就是目前最主流的生产级方案。
9. 最后的经验分享:多卡部署这条路上我踩过的几个坑
这篇教程写到这里,想再和大家聊聊我自己踩过坑之后沉淀下来的体会。
最大的体会是,多卡部署和单卡部署是完全不同的思维模式。单卡只需要关心一个GPU的显存、算力、带宽,多卡则变成了一个分布式调度问题。你不仅要操心每个GPU的资源分配,还要关心它们之间的通信效率。我在第一次做四卡TP部署时,傻乎乎地没有检查卡间通信的拓扑结构,结果发现有一张卡走的是PCIe总线而不是NVLink,推理性能和其他三张卡明显脱节,引发了难以排查的NCCL超时错误。后来我会专门先用nvidia-smi topo -m和NCCL_DEBUG=INFO去验证卡间通信质量,再正式上线。
第二个体会是要敢于用监控工具暴露问题,而不是靠感觉。我用vLLM的Prometheus指标跑了一段时间后,惊讶地发现自己设置的高并发请求并没有压到想要的吞吐量,瓶颈出在CPU的tokenizer和采样器上。通过Grafana面板直观地看到GPU空转和CPU满载后,我把采样请求改成了异步批处理,才把那部分性能解放出来。没有日志和监控的分布式系统,就像在开夜路不打远光灯,出问题全靠赌。
第三个体会是永远给显存留一点余量。我踩过一个非常惨痛的坑,把--gpu-memory-utilization设成0.99,看似把所有显存都用上了,结果一旦并发请求的KV Cache增长超过了预分配的池子,直接OOM崩溃。后来我改为0.9,并设置--max-num-seqs上限,腾出了显存空间给CUDA context和NCCL通信用,从此再也没有遇到过类似的报错。记住,显存用完必死,稳定运行比极致的资源利用率重要得多。
经验这种东西光看不算数,建议你拿到这篇文章之后,找一台至少双卡的机器,按我前三章的步骤先跑通一次TP=2部署,再逐步跑通TP=4和并发压测。等你自己亲手体验过模型从一张卡迁移到多张卡的过程,遇见过一两次OOM和NCCL报错之后,你对分布式推理的掌控感就真正建立起来了。