单机多卡
单机多卡指在一台服务器内使用多张 GPU 协同训练或推理 LLM。
它看起来只是“多插几张卡”,实际要同时处理三件事:
- 模型权重、激活和 KV Cache 如何切分。
- GPU 之间如何通信。
- 推理框架如何根据拓扑调度请求。
一句话总结:
单机多卡 = 显存扩容 + 吞吐扩展 + 通信开销管理
如果模型单卡放不下,多卡可以把模型切开;如果模型单卡能放下,多卡也可以用多副本提升吞吐。两种目标不同,对硬件和框架配置的要求也不同。
1. 为什么需要多卡
常见原因有三类。
1.1 单卡显存放不下
大模型推理至少需要放下:
权重显存 + KV Cache 显存 + 运行时 buffer + 冗余空间
例如 70B 级模型即使用 FP16 / BF16 权重,单卡通常也很难完整放下;即使用量化压缩权重,长上下文和高并发还会让 KV Cache 快速增长。
这时多卡主要用于“装下模型”,常用方式是 tensor parallel、pipeline parallel 或两者组合。
1.2 单卡吞吐不够
如果模型单卡能放下,但在线服务 QPS 或 tokens/s 不够,可以启动多个模型副本,让不同 GPU 处理不同请求。
这种方式更接近 data parallel 或多实例部署,优点是简单、稳定、跨卡通信少;缺点是每张卡都要放一份完整模型,显存利用率不一定最高。
1.3 需要更大的 batch 或更长上下文
推理服务的吞吐常常依赖 continuous batching、prefix cache、chunked prefill 等调度能力。
多卡可以提供更多显存给 KV Cache 和运行时调度,但并不保证线性扩展。长上下文场景下,瓶颈可能从权重显存转移到 KV Cache、跨卡通信或调度队列。
2. 常见并行方式
2.1 Tensor Parallel
Tensor parallel,简称 TP,会把同一层里的矩阵计算切到多张 GPU 上。
它的特点是:
- 每一层都可能发生跨卡通信。
- 对 GPU 互联带宽和延迟敏感。
- 适合单卡放不下权重,或者希望把单层计算摊到多张卡上。
- 在 NVLink / NVSwitch 环境中更容易获得收益。
推理框架里常见配置:
vllm serve /path/to/model --tensor-parallel-size 4
TP 的典型误区是“卡越多越快”。当模型不够大、batch 不够高,或者 GPU 之间只有较弱 PCIe 路径时,TP 通信开销可能抵消计算收益。
2.2 Pipeline Parallel
Pipeline parallel,简称 PP,会按层把模型切成多个 stage,不同 stage 放在不同 GPU 上。
它的特点是:
- 通信主要发生在相邻 stage 之间。
- 相比 TP,通信频率通常更低。
- 会引入流水线气泡。
- stage 负载不均衡时,慢 stage 会拖住整条流水线。
PP 更适合模型很深、单卡显存不足、且可以接受一定流水线调度开销的场景。推理中是否值得使用 PP,要结合 batch、并发、首 token 延迟和框架支持情况判断。
2.3 Data Parallel / 多副本
Data parallel 在训练中指每张 GPU 保存一份模型副本,处理不同 batch,并在反向传播时同步梯度。
在推理服务中,更常见的是多副本部署:
GPU0: 模型副本 A
GPU1: 模型副本 B
GPU2: 模型副本 C
GPU3: 模型副本 D
它的特点是:
- 跨卡通信少。
- 部署和排障简单。
- 更适合单卡能放下模型的在线推理。
- 吞吐扩展主要依赖负载均衡和请求调度。
如果模型单卡能放下,优先考虑多副本,通常比强行做 TP 更稳。
2.4 Expert Parallel
Expert parallel 常见于 MoE 模型,会把不同 expert 分布到不同 GPU 上。
它的特点是:
- token 会被路由到不同 expert。
- 常见通信模式是 all-to-all。
- 对互联、路由均衡和 batch 规模敏感。
- 激活参数少不等于通信开销低。
MoE 部署不能只看“激活参数量”。如果 expert 分散在多张卡上,token dispatch 和 combine 可能成为瓶颈。
3. 显存如何分布
多卡部署时,显存不是简单相加后随便使用。不同并行方式的显存分布不同。
| 方式 | 权重 | KV Cache | 通信开销 | 典型用途 |
|---|---|---|---|---|
| 多副本 | 每张卡一份完整模型 | 每个副本独立持有 | 很少 | 单卡能放下模型,扩吞吐 |
| TP | 权重按张量分片 | 通常按并行策略分布 | 高频 all-reduce / all-gather | 单卡放不下或需要分摊计算 |
| PP | 权重按层分片 | 跟随 stage 分布 | stage 间传激活 | 模型较深、显存不足 |
| EP | expert 分布在多卡 | 取决于框架实现 | all-to-all 明显 | MoE 模型 |
推理显存估算时至少要保守考虑:
- 权重是否量化。
- TP / PP 后每张卡的权重分片大小。
- 最大上下文长度。
- 最大并发请求数。
- KV Cache 精度和布局。
- CUDA graph、workspace、通信 buffer 等运行时开销。
4. 多卡通信开销
多卡真正的成本来自通信。
常见通信模式包括:
| 通信模式 | 说明 | 常见场景 |
|---|---|---|
| all-reduce | 多张卡聚合结果后再分发 | TP、数据并行训练 |
| all-gather | 收集各卡分片组成完整结果 | TP、参数分片 |
| reduce-scatter | 聚合后再按分片分发 | ZeRO、FSDP |
| all-to-all | 每张卡都和其他卡交换不同数据 | MoE expert parallel |
| point-to-point | 两张卡之间直接传递 | PP stage 间通信 |
通信开销会影响:
- TTFT,也就是首 token 延迟。
- decode 阶段 tokens/s。
- 高并发下的排队时间。
- 某些 GPU 利用率高、某些 GPU 等待的负载不均。
如果 GPU 之间只有 PCIe,TP 规模要谨慎扩大;如果是 NVLink / NVSwitch,TP 和混合并行的空间会更大。具体互联差异可参考 GPU互联。
5. GPU 拓扑检查
部署前建议先看拓扑。
nvidia-smi topo -m
常见标记大致可以这样理解:
| 标记 | 含义 |
|---|---|
NV# | GPU 之间通过 NVLink 连接,# 通常表示链路数量或级别 |
PIX | 经过同一个 PCIe switch |
PXB | 经过多个 PCIe bridge / switch |
PHB | 经过 PCIe host bridge |
SYS | 跨 NUMA 或跨 CPU socket,距离更远 |
经验判断:
- TP group 尽量放在
NV#或拓扑距离最近的 GPU 上。 - PP 相邻 stage 尽量放在通信距离近的 GPU 上。
- 多副本推理更关注每张卡是否均衡、CPU / NUMA / 网卡路径是否合理。
- 多机训练或跨节点推理还要看 GPU 与网卡的亲和性。
还可以补充查看:
nvidia-smi topo -p2p r
lspci -tv
numactl --hardware
如果机器是双路 CPU,多卡可能分布在不同 socket 后面。跨 socket 通信会增加延迟,也可能影响 GPU 到网卡、GPU 到 NVMe 的路径。
6. 推理框架配置
6.1 vLLM
vLLM 中最常见的是 tensor parallel。
vllm serve /path/to/model \
--tensor-parallel-size 4 \
--max-model-len 32768 \
--gpu-memory-utilization 0.90
常见思路:
- 单机 4 卡跑一个大模型:
--tensor-parallel-size 4。 - 单机 8 卡跑两个副本:启动两个服务进程,每个进程使用 4 张卡。
- 单卡能放下模型:优先多副本,而不是把 TP 拉大。
- OOM 时先降低
--max-model-len、并发、--gpu-memory-utilization或量化权重。
如果需要限制某个进程只看到部分 GPU,可以使用:
CUDA_VISIBLE_DEVICES=0,1,2,3 vllm serve /path/to/model --tensor-parallel-size 4
Windows PowerShell 写法不同:
$env:CUDA_VISIBLE_DEVICES="0,1,2,3"
vllm serve /path/to/model --tensor-parallel-size 4
6.2 TensorRT-LLM
TensorRT-LLM 通常需要在构建 engine 时确定 TP / PP 等并行配置。
简化理解:
构建阶段:确定模型切分方式和 engine
运行阶段:按对应 GPU 数量加载 engine 并启动服务
它适合追求较高性能、部署链路相对固定的生产场景。缺点是构建和调试成本通常高于直接用通用推理服务框架。
6.3 多进程多副本
多副本部署通常靠多个进程或多个容器实现。
示例:
进程 A: CUDA_VISIBLE_DEVICES=0,1 TP=2
进程 B: CUDA_VISIBLE_DEVICES=2,3 TP=2
进程 C: CUDA_VISIBLE_DEVICES=4,5 TP=2
进程 D: CUDA_VISIBLE_DEVICES=6,7 TP=2
前面再放一层 API 网关或负载均衡,把请求分发到不同副本。
这种方式适合:
- 单机 8 卡,但不想让一个模型实例吃满 8 卡。
- 需要隔离不同业务或不同模型。
- 希望滚动升级或灰度发布。
7. 常见部署组合
| 场景 | 推荐起点 | 说明 |
|---|---|---|
| 7B / 14B 单卡能放下 | 多副本 | 简单稳定,吞吐扩展直接 |
| 32B / 70B 单卡放不下 | TP=2/4/8 | 优先看互联和框架支持 |
| 超长上下文服务 | 降低副本数,预留 KV Cache | 重点控制 max model len 和并发 |
| MoE 模型 | TP + EP 或框架推荐配置 | 关注 all-to-all 和 expert 负载均衡 |
| 低延迟在线服务 | 小 TP 或多副本 | 避免通信过多拉高首 token 延迟 |
| 离线批处理 | 更大 batch + 合理 TP | 以 tokens/s 和成本为主 |
实践中建议从简单配置开始压测,而不是一开始就堆满所有并行方式。
8. 常见 OOM 问题
8.1 启动就 OOM
可能原因:
- 权重本身放不下。
- TP / PP 配置和 GPU 数量不匹配。
- 量化方式未生效。
max_model_len太大,框架预留了过多 KV Cache。gpu_memory_utilization设置过高,运行时没有冗余空间。
排查顺序:
- 确认实际加载精度和权重大小。
- 降低最大上下文长度。
- 降低 GPU 显存利用率上限。
- 减少并发或 batch。
- 再考虑增加 TP 或换更大显存 GPU。
8.2 运行一段时间后 OOM
可能原因:
- 并发峰值超过预期。
- 长上下文请求堆积。
- KV Cache 碎片或调度策略不合适。
- 多副本之间负载不均。
- 某些请求没有正确限制输入长度或输出长度。
建议在线服务必须限制:
- 最大输入 token。
- 最大输出 token。
- 最大并发。
- 单用户或单队列的请求速率。
- 超长请求的独立队列。
9. 常见性能问题
9.1 多卡比少卡还慢
常见原因:
- TP 规模过大,通信开销超过计算收益。
- GPU 拓扑不合理,跨了
SYS或远端 NUMA。 - batch 太小,无法摊薄通信成本。
- 推理框架没有正确识别 P2P 或 NCCL 通信路径。
处理方式:
- 降低 TP。
- 改成多副本。
- 调整
CUDA_VISIBLE_DEVICES选择更近的 GPU。 - 用真实业务请求重新压测,而不是只看空载 tokens/s。
9.2 GPU 利用率不均
常见原因:
- PP stage 切分不均。
- 某张卡承担了更多 KV Cache 或调度开销。
- 多副本负载均衡不均。
- CPU、NUMA 或网络路径导致某些卡等待数据。
排查时同时看:
- 每张 GPU 的利用率。
- 每张 GPU 的显存占用。
- 每个模型副本的请求队列。
- CPU 利用率和 tokenizer 开销。
- 拓扑与网卡位置。
9.3 首 token 慢
首 token 延迟主要受 prefill 影响,长 prompt、高并发、TP 通信和队列等待都会放大 TTFT。
可尝试:
- 控制最大输入长度。
- 使用 prefix cache。
- 给长 prompt 单独队列。
- 减小 TP 或改多副本。
- 调整 batching 策略。
10. 选型建议
单机多卡选型可以按这个顺序判断:
- 模型单卡能不能放下。
- 如果能放下,优先多副本扩吞吐。
- 如果放不下,先估算需要几张卡切权重。
- 检查 GPU 之间是 PCIe、NVLink 还是 NVSwitch。
- 根据互联选择 TP / PP / EP。
- 用真实上下文长度和并发压测。
- 最后再调整框架参数和部署副本数。
不要只按 GPU 数量做决策。4 张强互联 GPU 和 8 张弱互联 GPU,在 TP 场景下可能完全不是一个体验。
11. 总结
单机多卡的核心不是“把卡用满”,而是让并行方式、显存分布和 GPU 拓扑匹配业务目标。
如果目标是吞吐,单卡能放下时优先多副本;如果目标是放下大模型,再考虑 TP、PP 或混合并行;如果是 MoE,还要额外关注 expert 路由和 all-to-all 通信。
最终判断标准应来自压测:
目标模型 + 目标上下文 + 目标并发 + 真实请求分布
-> 显存占用、TTFT、tokens/s、稳定性
-> 决定单机多卡部署方式