vLLM 异构三卡部署实战4090D + 双 A100 使用 Pipeline Parallelism 方案(一)
导语摘要
在大模型本地部署场景中,很多服务器并不是标准的同构 GPU 配置,而是同时存在不同型号的显卡。例如一台机器中既有 RTX 4090D,又有 两张 A100-SXM4-40GB。
这种机器资源看起来很强,但真正部署 vLLM 时会遇到一个问题:
三张卡型号不同,能不能放在同一个 vLLM 实例里一起跑?
如果直接使用:
CUDA_VISIBLE_DEVICES=0,1,2
--tensor-parallel-size 3
看似简单,但在异构 GPU 场景下并不一定稳定。因为 Tensor Parallelism 会把同一层计算切到多张 GPU 上执行,对 GPU 性能一致性和通信能力要求更高。
本文整理一种更适合当前机器的方案:
方案 A:单实例三卡部署,使用 Pipeline Parallelism,配置为
TP=1,PP=3。
也就是:
CUDA_VISIBLE_DEVICES=0,1,2
--tensor-parallel-size 1
--pipeline-parallel-size 3
这套方案的目标不是盲目追求极限吞吐,而是先让 4090D + A100 + A100 三张异构 GPU 在同一个 vLLM 实例中稳定参与推理。
一、部署背景:为什么要做异构三卡
当前服务器 GPU 配置如下:
- GPU 0:NVIDIA GeForce RTX 4090 D
- GPU 1:NVIDIA A100-SXM4-40GB
- GPU 2:NVIDIA A100-SXM4-40GB
如果只追求稳定,其实最简单的方式是只使用两张 A100:
CUDA_VISIBLE_DEVICES=1,2
--tensor-parallel-size 2
这种部署方式属于双 A100 同构部署,稳定性较好,适合生产主服务。
但问题是,服务器上还有一张 4090D,如果完全不用,就会造成资源浪费。
因此我们希望实现:
- 三张 GPU 都参与
- 同一个 vLLM 实例对外提供服务
- 尽量规避异构 TP 带来的问题
- 通过 systemd 统一管理服务
- 使用 OpenAI 风格接口对外调用
这就是本文的方案 A。
二、为什么不推荐直接使用 TP=3
很多人看到三张 GPU,会直接想到:
CUDA_VISIBLE_DEVICES=0,1,2
--tensor-parallel-size 3
这表示把三张 GPU 放进同一个 Tensor Parallel 组里。
如果三张卡都是同型号,比如三张 A100,这种方式相对更容易理解和调优。
但当前机器是:
- 4090D
- A100
- A100
这属于异构 GPU 组合。
2.1 Tensor Parallelism 对 GPU 一致性要求更高
Tensor Parallelism 会把同一层的矩阵计算拆分到多张 GPU 上执行。
这意味着多张 GPU 之间需要频繁同步中间结果。
在异构 GPU 场景下,不同显卡之间存在差异:
- 架构不同
- 计算能力不同
- 显存规格不同
- 通信效率不同
- 单步计算耗时不同
最终可能导致一个问题:
快卡在等慢卡。
这会让整体性能不一定比双 A100 更好。
2.2 参数不一致时容易启动失败
如果你设置了:
--tensor-parallel-size 3
但是当前进程实际只看到了两张 GPU,就会出现类似错误:
World size (3) is larger than the number of available GPUs (2)
这个错误的意思非常直接:
- world size 是 3
- 但当前节点可用 GPU 只有 2
- 所以 vLLM 无法启动
这种问题通常由下面几种情况引起:
CUDA_VISIBLE_DEVICES只暴露了两张卡--tensor-parallel-size却设置成了 3- systemd 旧配置没有重新加载
- 实际生效的启动参数和预期不一致
因此,在异构三卡场景下,不建议一开始就直接上 TP=3。
三、方案 A 的核心思路
方案 A 的核心配置是:
CUDA_VISIBLE_DEVICES=0,1,2
--tensor-parallel-size 1
--pipeline-parallel-size 3
它的含义是:
- 三张 GPU 全部暴露给 vLLM
- 不做三卡张量并行
- 改用 Pipeline Parallelism
- 将模型按层切成三个阶段
- 每张 GPU 负责一个 pipeline stage
3.1 核心并行关系
vLLM 中可以简单理解为:
world_size = tensor_parallel_size × pipeline_parallel_size
本方案中:
world_size = 1 × 3 = 3
正好对应三张 GPU。
3.2 为什么 PP 更适合异构三卡
Pipeline Parallelism 是按模型层切分。
它不是把同一层计算强行拆给三张不同型号 GPU,而是让不同 GPU 负责模型的不同层段。
这样做有几个好处:
- 避免异构 GPU 直接进入同一个 Tensor Parallel 组
- 三张卡仍然可以参与同一个模型实例
- 部署结构更清晰
- 更适合先验证异构三卡可行性
不过也要注意:
Pipeline Parallelism 并不保证一定比双 A100 TP 更快。
因为如果某一个 pipeline stage 较慢,其他 stage 仍然可能等待。
所以方案 A 更适合:
- 异构三卡单实例验证
- 资源充分利用实验
- vLLM PP 部署实践
- 非极致吞吐优先场景
四、方案 A 总体架构图

图 1 展示了方案 A 的核心结构:
- vLLM API Server 对外提供统一接口
- GPU 0 的 4090D 作为 Pipeline Stage 0
- GPU 1 的 A100 作为 Pipeline Stage 1
- GPU 2 的 A100 作为 Pipeline Stage 2
- 整体配置为
TP=1,PP=3
这种方式让三张异构 GPU 都参与同一个 vLLM 实例。
五、最终 systemd 配置
下面是完整可用的 systemd 配置。
文件路径:
/etc/systemd/system/vllm-gemma.service
完整内容如下:
[Unit]
Description=vLLM Gemma GGUF Service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/data/models
Environment=CUDA_DEVICE_ORDER=PCI_BUS_ID
Environment=CUDA_VISIBLE_DEVICES=0,1,2
Environment=PYTHONUNBUFFERED=1
Environment=HF_HOME=/root/.cache/huggingface
ExecStart=/root/miniconda3/envs/vllm/bin/vllm serve /data/vllm/models/gemma-3-12b-it-qat-q4_0-gguf/gemma-3-12b-it-q4_0.gguf \
--tokenizer /data/vllm/models/gemma-3-27b-it \
--served-model-name gemma3-12b-q4 \
--tensor-parallel-size 1 \
--pipeline-parallel-size 3 \
--host 0.0.0.0 \
--port 8000 \
--api-key sk-gemma \
--language-model-only \
--max-model-len 16384 \
--gpu-memory-utilization 0.90 \
--max-num-seqs 64 \
--max-num-batched-tokens 16384
Restart=always
RestartSec=10
TimeoutStartSec=0
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
六、关键配置解释
6.1 固定 CUDA 设备顺序
Environment=CUDA_DEVICE_ORDER=PCI_BUS_ID
异构 GPU 环境下建议保留这个配置。
它可以让 CUDA 按 PCI Bus ID 顺序枚举设备,避免因为默认设备排序导致 GPU 编号和预期不一致。
6.2 暴露三张 GPU
Environment=CUDA_VISIBLE_DEVICES=0,1,2
这表示当前 vLLM 进程可以看到三张 GPU:
- GPU 0:4090D
- GPU 1:A100
- GPU 2:A100
如果写成:
Environment=CUDA_VISIBLE_DEVICES=1,2
那 vLLM 只能看到两张 A100,4090D 不会参与。
6.3 不做三卡 TP
--tensor-parallel-size 1
这表示不做 Tensor Parallelism。
6.4 使用三段 PP
--pipeline-parallel-size 3
这表示把模型按层切成三个 pipeline stage。
6.5 模型服务名保持一致
--served-model-name gemma3-12b-q4
这里建议服务名和实际模型保持一致。
因为实际加载的是:
gemma-3-12b-it-q4_0.gguf
如果服务名还写成类似:
gemma3:27b-it-q8_0
后续接口调用、日志排查、监控都会比较混乱。
6.6 删除 TRANSFORMERS_CACHE
不建议再配置:
Environment=TRANSFORMERS_CACHE=/root/.cache/huggingface
保留下面这一行即可:
Environment=HF_HOME=/root/.cache/huggingface
七、TP=3 与 PP=3 的对比

图 2 展示了两种部署思路:
第一种是直接 TP=3:
- 同一层计算拆到三张 GPU
- 对 GPU 一致性和通信要求更高
- 异构卡场景下可能被慢卡拖住
第二种是 TP=1,PP=3:
- 模型按层切成三段
- 三张 GPU 分别负责不同 stage
- 更适合异构三卡先跑通
因此,对于当前的 4090D + A100 + A100 组合,建议优先使用方案 A。
八、启动与验证方式
8.1 重新加载 systemd 配置
修改 service 后执行:
sudo systemctl daemon-reload
8.2 重启 vLLM 服务
sudo systemctl restart vllm-gemma.service
8.3 查看服务状态
sudo systemctl status vllm-gemma.service -n 100 --no-pager
重点观察是否出现:
- Python traceback
- world size 报错
- CUDA 报错
- 显存不足
- 模型路径错误
- tokenizer 路径错误
8.4 实时查看日志
journalctl -u vllm-gemma.service -f
8.5 观察 GPU 使用情况
watch -n 1 nvidia-smi
正常情况下,三张卡都应该出现 vLLM 进程,并且显存会有明显占用。
请求进入时,三张卡的 GPU Util 会出现一定波动。
8.6 测试模型列表接口
curl http://127.0.0.1:8000/v1/models \
-H "Authorization: Bearer sk-gemma"
正常情况下会返回类似:
{
"object": "list",
"data": [
{
"id": "gemma3-12b-q4",
"object": "model"
}
]
}
8.7 测试对话接口
curl http://127.0.0.1:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-gemma" \
-d '{
"model": "gemma3-12b-q4",
"messages": [
{
"role": "user",
"content": "请用100字解释什么是 Pipeline Parallelism"
}
],
"temperature": 0.7,
"max_tokens": 256
}'
如果可以正常返回内容,说明 vLLM OpenAI 风格接口已经可用。
九、部署与验证流程图

图 3 展示了方案 A 的完整部署流程:
- 修改 systemd service
- 设置三卡可见
- 配置
TP=1,PP=3 - 重载 systemd
- 重启 vLLM 服务
- 查看日志
- 使用
nvidia-smi观察三张卡 - 使用 curl 测试接口
这个流程可以作为后续所有 vLLM 服务调试的基础模板。
十、常见问题排查
10.1 报错:World size 大于可见 GPU 数量
典型错误:
World size (3) is larger than the number of available GPUs (2)
原因是:
- 并行参数要求 3 张 GPU
- 但当前进程只看到 2 张 GPU
常见错误配置:
CUDA_VISIBLE_DEVICES=1,2
--tensor-parallel-size 3
修复方式:
CUDA_VISIBLE_DEVICES=0,1,2
--tensor-parallel-size 1
--pipeline-parallel-size 3
同时确认 systemd 已经重新加载:
sudo systemctl daemon-reload
sudo systemctl restart vllm-gemma.service
10.2 服务还是使用旧参数
如果你已经改了 service,但日志里还是出现旧参数,可能是没有执行:
sudo systemctl daemon-reload
建议直接查看当前 systemd 实际加载的配置:
sudo systemctl cat vllm-gemma.service
确认里面是否仍然存在旧参数,比如:
--tensor-parallel-size 3
10.3 仍然出现 TRANSFORMERS_CACHE 警告
如果日志里仍然看到:
Using TRANSFORMERS_CACHE is deprecated
说明配置里还残留:
Environment=TRANSFORMERS_CACHE=/root/.cache/huggingface
删除它,只保留:
Environment=HF_HOME=/root/.cache/huggingface
然后重新加载服务:
sudo systemctl daemon-reload
sudo systemctl restart vllm-gemma.service
10.4 三张卡显存不完全一致
这是正常现象。
Pipeline Parallelism 是按层切分模型,不是让每张卡做完全一样的事情。
因此三张 GPU 的显存占用、GPU Util 不一定完全相同。
只要满足下面条件,就说明服务基本正常:
- 三张 GPU 都有 vLLM 进程
- 三张 GPU 都有显存占用
- 请求能够正常返回
- 日志没有持续报错
10.5 服务启动慢
vLLM 启动时需要加载模型、初始化 tokenizer、分配 KV cache、构建执行图,因此大模型首次启动慢是正常现象。
建议通过下面命令观察:
journalctl -u vllm-gemma.service -f
如果长时间卡住,可以重点检查:
- 模型路径是否正确
- tokenizer 路径是否正确
- 显存是否不足
- 是否开启了过大的
max-model-len - 是否设置了过大的
max-num-seqs
十一、性能调优建议
11.1 首次启动建议保守一点
如果是第一次验证异构三卡 PP,建议先用保守配置:
--max-model-len 8192
--gpu-memory-utilization 0.85
--max-num-seqs 32
--max-num-batched-tokens 8192
等服务稳定后,再逐步提高到:
--max-model-len 16384
--gpu-memory-utilization 0.90
--max-num-seqs 64
--max-num-batched-tokens 16384
11.2 不要默认认为三卡 PP 一定更快
方案 A 的重点是:
- 三张卡都参与
- 单实例部署
- 异构 GPU 验证
- 模型按层切分
但它不一定比双 A100 TP=2 更快。
原因是 PP 会受到最慢 stage 的影响。
如果 4090D 所在 stage 较慢,两张 A100 可能需要等待。
所以建议你实际对比:
| 方案 | 配置 | 特点 | 适合场景 |
|---|---|---|---|
| 双 A100 TP | CUDA_VISIBLE_DEVICES=1,2 + TP=2 |
稳定、简单、性能好 | 生产主服务 |
| 三卡 TP | CUDA_VISIBLE_DEVICES=0,1,2 + TP=3 |
看起来简单,但异构不稳 | 不建议优先使用 |
| 三卡 PP | CUDA_VISIBLE_DEVICES=0,1,2 + TP=1,PP=3 |
三卡都参与,适合异构验证 | 本文方案 A |
| 双实例分流 | A100 实例 + 4090D 实例 | 更灵活、更适合长期生产 | 进阶方案 |
11.3 建议压测指标
后续可以重点观察这些指标:
- 首 token 延迟
- 平均 tokens/s
- 并发请求数
- GPU 利用率
- 显存占用
- 请求失败率
- 请求排队时间
- vLLM 日志中的调度信息
测试时建议分别对比:
- 双 A100 TP=2
- 三卡 PP=3
- 单 4090D
- 单 A100
- 双实例分流
这样才能判断当前方案是否真的适合你的业务请求类型。
十二、适合放到文章中的最终配置总结
本文最终采用的部署方式是:
CUDA_DEVICE_ORDER=PCI_BUS_ID
CUDA_VISIBLE_DEVICES=0,1,2
vLLM 并行参数是:
--tensor-parallel-size 1
--pipeline-parallel-size 3
完整目标是:
- 4090D 参与
- 两张 A100 参与
- 单实例部署
- 不做异构 TP
- 使用 Pipeline Parallelism 按层切分
- 通过 OpenAI 风格接口对外服务
十三、总结
对于 RTX 4090D + 双 A100 这种异构 GPU 服务器,最直观的想法是直接使用:
--tensor-parallel-size 3
但这种方式不一定适合异构场景。
更稳妥的方案是:
--tensor-parallel-size 1
--pipeline-parallel-size 3
也就是本文的方案 A。
它的核心价值在于:
- 三张 GPU 都能参与同一个 vLLM 实例
- 避免异构 GPU 直接进入同一个 Tensor Parallel 组
- 配置相对清晰
- 适合先验证三卡异构推理可行性
- 方便后续和双 A100 TP=2 做性能对比
不过也要明确:
方案 A 不一定是极致吞吐最优解,它更适合作为异构三卡单实例部署的验证方案。
如果后续追求长期生产稳定,可以继续演进为:
- A100 + A100 作为主推理服务
- 4090D 作为独立副服务
- 前面通过 API 网关按请求类型分流
这样既能利用所有 GPU,也能让整体架构更加稳定、可控、易维护。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)