「两张显卡部署两个模型」有两种完全不同的需求:两个模型各占一张卡(服务隔离),或一个模型切到两张卡(显存扩容)。前者用两个独立推理实例分别绑卡,后者用张量并行。本文给出三条路线的选择树、可直接使用的 vLLM + Nginx 配置、MIG 的硬约束,以及一套隔离性验收脚本。

图注:物理分卡与张量并行拓扑(来源:商红科技行业论坛原文配图;非实测)

图注:双卡部署形态(来源:商红科技行业论坛原文配图;非实测)
先说结论
- 两个模型都能单卡装下:优先物理分卡,起两个独立实例,各绑一张卡;
- 需要硬件级隔离且机器是 Linux:考虑 MIG 切片(仅 RTX PRO 系列支持);
- 只有一个模型、单卡装不下:才用张量并行,它解决的不是「两个模型共存」。
把张量并行当成「双卡部署两个模型」的答案,是最常见的误用:--tensor-parallel-size 2 会把两张卡绑成一个资源池,第二个模型反而没地方放。
一、三条路线对比
| MIG 切片 | 物理分卡 | 张量并行 | |
|---|---|---|---|
| 解决什么 | 单卡切成多个独立实例 | 一张卡跑一个独立服务 | 一个模型横跨多卡 |
| 单模型显存上限 | 受切片限制(最小 24GB) | 整卡 | 多卡之和 |
| 需要 Linux | 是 | 否 | 否 |
| 故障隔离 | 硬件级 | 进程级 | 无,一起挂 |
| 适合 | 多个小模型各自独立 | 两个中等模型各占一卡 | 一个大模型要提速 |
一个关键约束:MIG 不能与张量并行叠加。MIG 不支持 NCCL,而 NCCL 是跨 GPU 集合通信的基础库,所以「先切片再跨切片做并行」走不通。
二、物理分卡:最小可用配置
vLLM 官方说明,单个端口同时提供多个模型目前不受支持,官方推荐的做法是运行多个服务器实例,再在前面加一层路由。
两个实例分别绑定不同 GPU:
# 实例 A:绑定 0 号卡
CUDA_VISIBLE_DEVICES=0 vllm serve <model-a> \
--port 8000 --gpu-memory-utilization 0.90 --max-model-len 32768
# 实例 B:绑定 1 号卡
CUDA_VISIBLE_DEVICES=1 vllm serve <model-b> \
--port 8001 --gpu-memory-utilization 0.90 --max-model-len 32768
用 Docker Compose 固化:
services:
model-a:
image: vllm/vllm-openai:latest
command: ["--model", "<model-a>", "--port", "8000",
"--gpu-memory-utilization", "0.90", "--max-model-len", "32768"]
environment:
- CUDA_VISIBLE_DEVICES=0
ports:
- "8000:8000"
ipc: host
shm_size: "16gb"
model-b:
image: vllm/vllm-openai:latest
command: ["--model", "<model-b>", "--port", "8001",
"--gpu-memory-utilization", "0.90", "--max-model-len", "32768"]
environment:
- CUDA_VISIBLE_DEVICES=1
ports:
- "8001:8001"
ipc: host
shm_size: "16gb"
Nginx 按路径分流:
upstream model_a { server 127.0.0.1:8000; }
upstream model_b { server 127.0.0.1:8001; }
server {
listen 8080;
location /model-a/ {
proxy_pass http://model_a/;
proxy_buffering off;
proxy_read_timeout 600s;
proxy_set_header Host $host;
}
location /model-b/ {
proxy_pass http://model_b/;
proxy_buffering off;
proxy_read_timeout 600s;
proxy_set_header Host $host;
}
}
proxy_buffering off 很重要:默认缓冲会让流式输出变成「等很久然后一次性吐完」,看起来像推理卡住。
三、MIG:硬数字与硬约束
以 RTX PRO 6000 96GB 为例,单卡可切 4 个 24GB 实例;RTX PRO 5000 48GB 单卡可切 2 个 24GB 实例。注意同名档位 1g.24gb 在 96GB 卡上占 1/4、在 48GB 卡上占 1/2,按名字估并发会算错。
启用后检查:
nvidia-smi -i 0 --query-gpu=mig.mode.current --format=csv
nvidia-smi mig -lgi
三条必须提前知道的约束:
- MIG 仅支持 CUDA 支持的 Linux 发行版,Windows 不支持;
- NCCL 目前不与 MIG 兼容;
- 跨 GPU 的 MIG 实例之间不支持 P2P,只有同一张卡内部的实例支持。
所以 MIG 适合「多个小模型各自独立」,不适合「两个模型要协同」,也不适合 Windows。
四、张量并行:什么时候才该用
CUDA_VISIBLE_DEVICES=0,1 vllm serve <large-model> \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.90
它把模型的权重矩阵切开分摊到两张卡,产出是「一个模型跑起来了」。判断是否该用,只问一句:单个模型是否真的单卡装不下。如果两个模型都能单卡装下,用张量并行只会把两张卡绑死。
另外要确认互联条件:部分专业卡规格表里没有 NVLink,跨卡通信只能走 PCIe。张量并行的效率高度依赖卡间带宽,部署前先查拓扑。
五、验收:隔离性必须验证
#!/usr/bin/env bash
set -e
echo "[1] GPU 设备分配"
nvidia-smi --query-gpu=index,name,memory.used,memory.total --format=csv
echo "[2] 两个实例健康检查"
curl -sf http://127.0.0.1:8000/health
curl -sf http://127.0.0.1:8001/health
echo "[3] 隔离性:停掉 A,B 应仍可用"
docker compose stop model-a
curl -sf http://127.0.0.1:8001/health
echo "[4] 恢复 A"
docker compose start model-a
echo "[5] 长上下文压测后看显存余量"
curl -s http://127.0.0.1:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"<model-a>","messages":[{"role":"user","content":"<long prompt>"}],"max_tokens":512}' \
> /dev/null
nvidia-smi --query-gpu=index,memory.used,memory.total --format=csv
第 3 项最容易被跳过,却恰恰是「两个模型共存」的核心价值。如果停掉 A 会影响 B,说明两个实例仍共享了某个资源(同一张卡、同一个端口、同一个缓存目录),隔离没有成立。
六、四个高频配置错误
CUDA_VISIBLE_DEVICES 会重编号。 设成 =1 后,进程内看到的是 cuda:0,不是 cuda:1。代码里再写死 cuda:1 会报设备不存在。
两个实例抢同一张卡。 启动前用 nvidia-smi 确认每个进程的 PID 对应的 GPU 编号,不要只看环境变量。
鉴权与配额下放到模型进程。 更稳妥的做法是在网关层维护「密钥 → 可用模型 → 速率上限」,每个实例独立密钥。
双路机器不做 NUMA 绑定。 卡挂在哪个 CPU 下就绑哪个节点,减少跨节点取数;这是可选优化,但双路机上收益通常明显。
边界与适用条件
- 文中命令以 vLLM 的 OpenAI 兼容服务为例,其他框架的参数名不同。
- MIG 的实例档位随驱动与显卡型号变化,部署前以
nvidia-smi mig -lgip和官方文档为准。 - 两个模型型号不同时必须走物理分卡,张量并行要求同型号同显存。
工程落地中的一个选择
如果要在双卡工作站上做多模型服务,建议先按「三个问题定路线」自查,再用上面的脚本做一次隔离性验收。商红科技做工作站与服务器的选型交付,可以按模型数量、显存和卡间互联条件把路线与整机约束一起过一遍;这条选型路径的推导过程,在行业论坛原文里有更完整的版本。最终配置仍应以你自己的压测结果为准。
商红科技能接的是双卡整机的选型、驱动/环境适配与交付验收这一段;应用层网关与业务路由仍由你的研发团队维护。