分布式部署
当单个 GPU 无法容纳模型,或者需要处理更高的并发请求时,分布式部署是必要的。本章详细介绍 vLLM 的分布式推理策略,帮助你根据实际场景选择最合适的部署方案。
分布式推理策略选择
选择分布式推理策略时,需要根据模型大小和硬件资源来判断:
单 GPU 场景
如果模型能够在单个 GPU 上运行,通常不需要分布式推理。直接在该 GPU 上运行即可。
单节点多 GPU 场景
当模型太大无法放在单个 GPU 上,但可以在单个节点的多个 GPU 上运行时,使用张量并行(Tensor Parallelism)。例如,在使用 4 个 GPU 的节点上设置 tensor_parallel_size=4。
张量并行的优势在于节点内 GPU 之间的高速通信(如 NVLink),能够实现高效的模型权重分割和计算。
多节点场景
当模型太大无法放在单个节点上时,需要结合张量并行和流水线并行(Pipeline Parallelism)。将 tensor_parallel_size 设置为每个节点的 GPU 数量,将 pipeline_parallel_size 设置为节点数量。
例如,使用 2 个节点,每个节点 8 个 GPU 时,设置 tensor_parallel_size=8 和 pipeline_parallel_size=2。
选择策略总结
| 场景 | 推荐策略 | 配置示例 |
|---|---|---|
| 单 GPU | 无需分布式 | 默认配置 |
| 单节点多 GPU | 张量并行 | tensor_parallel_size=4 |
| 多节点 | 张量并行 + 流水线并行 | tensor_parallel_size=8, pipeline_parallel_size=2 |
| 高并发服务 | 数据并行 | data_parallel_size=4 |
| MoE 大模型 | 数据并行 + 专家并行 | --data-parallel-size=4 --enable-expert-parallel |
特殊情况:不均匀 GPU 分配
如果模型可以在单个节点内运行,但 GPU 数量无法均匀分割模型大小,可以启用流水线并行。流水线并行按层分割模型,支持不均匀分割。在这种情况下,设置 tensor_parallel_size=1,将 pipeline_parallel_size 设置为 GPU 数量。
此外,如果节点上的 GPU 没有 NVLink 互联(如 L40S),使用流水线并行而非张量并行可以获得更高的吞吐量和更低的通信开销。
张量并行(Tensor Parallelism)
张量并行将模型的权重矩阵沿维度分割到多个 GPU 上,是最常用的分布式推理策略。
工作原理
张量并行的核心思想是将大型矩阵运算分解为多个小型矩阵运算,分配到不同 GPU 上并行执行。
模型层: Linear(in=4096, out=4096)
张量并行 (TP=2):
GPU 0: Linear(in=4096, out=2048) ← 计算一半输出
GPU 1: Linear(in=4096, out=2048) ← 计算另一半输出
↓
All-Reduce 合并结果 ← 通信同步
vLLM 的张量并行实现基于 Megatron-LM 的算法,这是一种成熟的张量并行方案。
单节点多卡配置
命令行启动:
# 2 卡张量并行
vllm serve meta-llama/Llama-2-70b-chat-hf \
--tensor-parallel-size 2
# 4 卡张量并行
vllm serve meta-llama/Llama-2-70b-chat-hf \
--tensor-parallel-size 4
Python API:
from vllm import LLM
llm = LLM(
model="meta-llama/Llama-2-70b-chat-hf",
tensor_parallel_size=4
)
outputs = llm.generate("Hello, world!")
显存计算
张量并行可以将显存占用均分到多个 GPU:
模型: Llama-2-70B
FP16 显存: ~140GB
TP=2: 每个 GPU ~70GB (需要 A100 80GB 或更大)
TP=4: 每个 GPU ~35GB (适合 A100 40GB)
TP=8: 每个 GPU ~18GB (适合 RTX 3090/4090 24GB)
性能优化建议
使用 NVLink:确保 GPU 之间有 NVLink 互联,可以显著提升张量并行的通信效率。没有 NVLink 时,通信通过 PCIe 进行,速度较慢。
检查日志输出:启动 vLLM 后,查看类似以下的日志消息:
INFO 07-23 13:56:04 [kv_cache_utils.py:775] GPU KV cache size: 643,232 tokens
INFO 07-23 13:56:04 [kv_cache_utils.py:779] Maximum concurrency for 40,960 tokens per request: 15.70x
GPU KV cache size报告 GPU KV 缓存中一次可存储的 token 总数Maximum concurrency估算如果每个请求需要指定数量的 token(示例中为 40,960),可以并发服务的请求数量
如果这些数字低于你的吞吐量要求,需要增加 GPU 或节点数量。
流水线并行(Pipeline Parallelism)
流水线并行将模型的不同层分配到不同 GPU,适合层数较多的模型。
工作原理
模型: 80 层 Transformer
流水线并行 (PP=4):
GPU 0: 层 0-19 ← 处理前 1/4 层
GPU 1: 层 20-39 ← 处理第 2 个 1/4 层
GPU 2: 层 40-59 ← 处理第 3 个 1/4 层
GPU 3: 层 60-79 ← 处理最后 1/4 层
数据流: GPU 0 → GPU 1 → GPU 2 → GPU 3 → 输出
与张量并行不同,流水线并行不需要频繁的 All-Reduce 通信,但会引入流水线气泡(Pipeline Bubble),影响效率。
使用场景
流水线并行特别适合以下情况:
- GPU 没有 NVLink 互联:如 L40S GPU,使用流水线并行可以获得更高的吞吐量
- GPU 数量不能整除模型大小:流水线并行支持不均匀分割
- 多节点部署:减少跨节点通信开销
配置方法
命令行启动:
vllm serve meta-llama/Llama-2-70b-chat-hf \
--pipeline-parallel-size 4
Python API:
from vllm import LLM
llm = LLM(
model="meta-llama/Llama-2-70b-chat-hf",
pipeline_parallel_size=4
)
混合并行
可以同时使用张量并行和流水线并行,以充分利用硬件资源。
配置示例
配置: TP=2, PP=2, 共 4 个 GPU
GPU 0 (TP Rank 0, PP Rank 0): 层 0-39 的前半部分
GPU 1 (TP Rank 1, PP Rank 0): 层 0-39 的后半部分
GPU 2 (TP Rank 0, PP Rank 1): 层 40-79 的前半部分
GPU 3 (TP Rank 1, PP Rank 1): 层 40-79 的后半部分
命令行启动:
vllm serve meta-llama/Llama-2-70b-chat-hf \
--tensor-parallel-size 2 \
--pipeline-parallel-size 2
Python API:
from vllm import LLM
llm = LLM(
model="meta-llama/Llama-2-70b-chat-hf",
tensor_parallel_size=2,
pipeline_parallel_size=2
)
混合并行最佳实践
单节点内优先使用张量并行:节点内 GPU 通常有 NVLink 互联,张量并行效率更高。
跨节点使用流水线并行:跨节点通信延迟较高,流水线并行可以减少通信次数。
数据并行(Data Parallelism)
数据并行用于扩展服务能力,每个副本独立处理请求,适合高并发场景。
工作原理
┌─────────────┐
│ 客户端 │
└──────┬──────┘
│
┌──────▼──────┐
│ 负载均衡器 │
└──────┬──────┘
┌───────────────┼───────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ 副本 1 │ │ 副本 2 │ │ 副本 3 │
│ (GPU 0) │ │ (GPU 1) │ │ (GPU 2) │
└─────────────┘ └─────────────┘ └─────────────┘
每个数据并行副本拥有完整的模型权重,独立处理一批请求。这种模式特别适合:
- 模型可以在单个 GPU 上运行
- 需要处理大量并发请求
- 要求低延迟响应
内部负载均衡模式
vLLM 支持"自包含"的数据并行部署,暴露单个 API 端点。
单节点配置:
# DP=4,需要 4 个 GPU
vllm serve meta-llama/Llama-2-7b-chat-hf \
--data-parallel-size 4
# 结合张量并行: DP=4, TP=2,需要 8 个 GPU
vllm serve meta-llama/Llama-2-13b-chat-hf \
--data-parallel-size 4 \
--tensor-parallel-size 2
多节点配置:
# 节点 0 (IP: 10.99.48.128) - 运行 DP ranks 0 和 1
vllm serve $MODEL --data-parallel-size 4 --data-parallel-size-local 2 \
--data-parallel-address 10.99.48.128 --data-parallel-rpc-port 13345
# 节点 1 - 运行 DP ranks 2 和 3
vllm serve $MODEL --headless --data-parallel-size 4 --data-parallel-size-local 2 \
--data-parallel-start-rank 2 \
--data-parallel-address 10.99.48.128 --data-parallel-rpc-port 13345
使用 Ray 进行数据并行
# 使用 Ray 作为后端
vllm serve meta-llama/Llama-2-7b-chat-hf \
--data-parallel-size 4 \
--data-parallel-backend ray
使用 Ray 的优势:
- 只需要在任意节点执行一次启动命令
- 不需要手动指定
--data-parallel-address - 自动分配远程 DP ranks
外部负载均衡模式
对于大规模部署,可以将每个 DP rank 视为独立的 vLLM 部署,使用外部负载均衡器分发请求。
单节点多实例:
# Rank 0
CUDA_VISIBLE_DEVICES=0 vllm serve $MODEL --data-parallel-size 2 --data-parallel-rank 0 \
--port 8000
# Rank 1
CUDA_VISIBLE_DEVICES=1 vllm serve $MODEL --data-parallel-size 2 --data-parallel-rank 1 \
--port 8001
多节点配置:
# 节点 0 (Rank 0)
vllm serve $MODEL --data-parallel-size 2 --data-parallel-rank 0 \
--data-parallel-address 10.99.48.128 --data-parallel-rpc-port 13345 \
--port 8000
# 节点 1 (Rank 1)
vllm serve $MODEL --data-parallel-size 2 --data-parallel-rank 1 \
--data-parallel-address 10.99.48.128 --data-parallel-rpc-port 13345 \
--port 8000
负载均衡配置
使用 Nginx 进行负载均衡:
upstream vllm_backend {
least_conn; # 最少连接数策略,适合长连接场景
server 10.99.48.128:8000;
server 10.99.48.128:8001;
server 10.99.48.129:8000;
server 10.99.48.129:8001;
}
server {
listen 80;
location /v1/ {
proxy_pass http://vllm_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 流式输出支持
proxy_buffering off;
proxy_cache off;
}
}
数据并行注意事项
--max-num-seqs 参数:该参数应用于每个 DP rank,而非全局。例如,设置 --max-num-seqs=256 且 --data-parallel-size=4,实际最大并发请求数为 1024。
负载均衡策略:vLLM 内部负载均衡基于每个引擎的运行队列和等待队列状态。更智能的负载均衡可以考虑 KV 缓存状态,最大化前缀缓存的效果。
API 服务器瓶颈:大规模 DP 部署时,API 服务器进程可能成为瓶颈。可以使用 --api-server-count 扩展 API 服务器:
vllm serve $MODEL --data-parallel-size 16 --api-server-count 4
MoE 模型的分布式部署
混合专家(Mixture of Experts,MoE)模型有特殊的并行需求。vLLM 支持为注意力层使用数据并行,为专家层使用专家并行或张量并行。
专家并行(Expert Parallelism)
对于采用多头潜在注意力(MLA)的 MoE 模型(如 DeepSeek),使用数据并行处理注意力层,使用专家并行或张量并行处理专家层更为高效。
# 启用专家并行
vllm serve deepseek-ai/deepseek-moe-16b-chat \
--data-parallel-size 4 \
--enable-expert-parallel
默认情况下,专家层形成大小为 DP × TP 的张量并行组。启用 --enable-expert-parallel 后,专家层使用专家并行。
MoE 模型的同步要求
对于 MoE 模型,当任何 rank 正在处理请求时,其他没有请求的 rank 必须执行空的"虚拟"前向传播。这通过单独的 DP 协调器进程处理,每 N 步执行一次集合操作来确定所有 rank 何时变为空闲状态。
多节点部署详解
当单节点 GPU 不足以容纳模型时,需要跨多节点部署。
环境准备
确保环境一致:每个节点必须提供相同的执行环境,包括模型路径和 Python 包。推荐使用容器镜像来保持环境一致性并隐藏主机异构性。
SSH 免密登录:
# 在 head 节点生成密钥
ssh-keygen -t rsa
# 复制到 worker 节点
ssh-copy-id user@worker-node-ip
使用 Ray 集群
Ray 是一个分布式计算框架,vLLM 使用 Ray 来管理跨多节点的分布式执行。
启动 Ray 集群:
# Head 节点
ray start --head --port=6379
# Worker 节点
ray start --address="head-node-ip:6379"
验证集群状态:
ray status
ray list nodes
运行 vLLM:
vllm serve /path/to/model \
--tensor-parallel-size 8 \
--pipeline-parallel-size 2 \
--distributed-executor-backend ray
使用 multiprocessing 后端
除了 Ray,vLLM 也支持使用 Python 的 multiprocessing 作为分布式运行时。
Head 节点:
vllm serve /path/to/model \
--tensor-parallel-size 8 \
--pipeline-parallel-size 2 \
--nnodes 2 \
--node-rank 0 \
--master-addr <HEAD_NODE_IP>
Worker 节点:
vllm serve /path/to/model \
--tensor-parallel-size 8 \
--pipeline-parallel-size 2 \
--nnodes 2 \
--node-rank 1 \
--master-addr <HEAD_NODE_IP> \
--headless
网络通信优化
高效的张量并行需要快速的节点间通信,最好通过高速网络适配器(如 InfiniBand)。
配置 InfiniBand:
# 添加 InfiniBand 相关参数
bash run_cluster.sh \
vllm/vllm-openai \
<HEAD_NODE_IP> \
--head \
/path/to/huggingface \
--privileged \
-e NCCL_IB_HCA=mlx5
启用 GPUDirect RDMA
GPUDirect RDMA 允许网络适配器直接访问 GPU 内存,绕过 CPU 和系统内存,减少延迟。
Docker 配置:
docker run --privileged \
--cap-add=IPC_LOCK \
--shm-size=host \
-v /dev/shm:/dev/shm \
...
Kubernetes 配置:
spec:
containers:
- name: vllm
image: vllm/vllm-openai
securityContext:
capabilities:
add: ["IPC_LOCK"]
volumeMounts:
- mountPath: /dev/shm
name: dshm
resources:
limits:
nvidia.com/gpu: 8
volumes:
- name: dshm
emptyDir:
medium: Memory
验证 GPUDirect RDMA:
# 启用 NCCL 详细日志
NCCL_DEBUG=TRACE vllm serve ...
# 检查日志
# 如果看到 "[send] via NET/IB/GDRDMA" - 正在使用 GPUDirect RDMA
# 如果看到 "[send] via NET/Socket" - 使用 TCP socket,效率较低
分布式后端选择
vLLM 支持多种分布式后端:
| 后端 | 配置 | 适用场景 |
|---|---|---|
| multiprocessing | --distributed-executor-backend mp | 单节点多 GPU(默认) |
| Ray | --distributed-executor-backend ray | 多节点部署 |
| UniNG | --distributed-executor-backend unig | 特定硬件优化 |
单节点默认使用 multiprocessing:对于单节点多 GPU 推理,vLLM 默认使用 Python 的 multiprocessing。
多节点推荐使用 Ray:Ray 提供更好的分布式调度和容错能力。
故障排查
常见问题
问题:GPU 内存不足
解决方案:
- 增加
tensor_parallel_size - 降低
max_model_len - 启用量化(如 AWQ、GPTQ)
- 降低
gpu_memory_utilization
问题:节点间通信超时
解决方案:
- 检查网络连接和防火墙配置
- 确保 InfiniBand 正确配置
- 增加 NCCL 超时时间:
NCCL_TIMEOUT=1800
问题:Ray 集群节点不可见
解决方案:
- 检查
ray status输出 - 确保 VLLM_HOST_IP 设置正确
- 检查节点间网络可达性
调试技巧
启用详细日志:
# 启用 NCCL 调试日志
NCCL_DEBUG=INFO vllm serve ...
# 启用 vLLM 调试日志
VLLM_LOGGING_LEVEL=DEBUG vllm serve ...
检查 KV 缓存状态:
启动后查看日志中的 KV 缓存信息,了解实际可用于推理的 token 容量。
小结
分布式部署的关键决策点:
- 策略选择:根据模型大小和硬件配置选择张量并行、流水线并行或数据并行
- 单节点优先张量并行:节点内有 NVLink 时效率最高
- 跨节点使用流水线并行:减少跨节点通信开销
- 高并发使用数据并行:独立副本处理请求,扩展服务能力
- MoE 模型特殊处理:结合数据并行和专家并行
- 网络优化:使用 InfiniBand 和 GPUDirect RDMA 提升跨节点通信效率