集群拓扑
| 节点 | RoCE IP | 管理 IP | 角色 |
|---|---|---|---|
| Head (节点二) | xxx.xxx.x.2 | xxx.xxx.x.102 | Ray Head + vLLM |
| Worker (节点一) | xxx.xxx.x.1 | xxx.xxx.x.101 | Ray Worker |
💡 网络说明:RoCE 直连网卡
enP2p1s0f1np1(200G),RDMA 网卡 mlx5_2(内部 RDMA 网段,NCCL 自动检测)。Docker 镜像 vllm-node-tf5:latest,模型路径 /model/<model-name>。
第一步 — 清理旧状态
每次启动前必须清理残留容器:
节点二 (Head):
docker rm -f vllm 2>/dev/null
节点一 (Worker):
ssh user@xxx.xxx.x.101 "docker rm -f vllm-worker 2>/dev/null"
第二步 — 启动 Ray 集群
节点二 (Head)
docker run -d --name vllm --gpus all --network host --ipc=host --privileged \
-v /model:/model \
-e VLLM_HOST_IP=xxx.xxx.x.2 \
-e GLOO_SOCKET_IFNAME=enP2p1s0f1np1 \
-e NCCL_SOCKET_IFNAME=enP2p1s0f1np1 \
vllm-node-tf5:latest \
ray start --head --node-ip-address xxx.xxx.x.2 --port 6379 --block
节点一 (Worker)
ssh user@xxx.xxx.x.101 "docker run -d --name vllm-worker --gpus all --network host --ipc=host --privileged \
-v /model:/model -e VLLM_HOST_IP=xxx.xxx.x.1 \
vllm-node-tf5:latest \
ray start --address xxx.xxx.x.2:6379 --node-ip-address xxx.xxx.x.1 --block"
⚠️ 关键:
GLOO_SOCKET_IFNAME 和 NCCL_SOCKET_IFNAME 必须在 docker run -e 级别设置,不能只在 docker exec 时传递。vLLM 的 ray_env.py 白名单只复制 NCCL_/VLLM_ 前缀的变量。
第三步 — 验证 Ray 集群
docker exec vllm ray status
必须看到:
- Active: 2 nodes
- GPU: 2.0
第四步 — 启动 vLLM 服务
在 Head 容器内执行(后台模式):
docker exec -d vllm bash -c "
VLLM_HOST_IP=xxx.xxx.x.2 \
GLOO_SOCKET_IFNAME=enP2p1s0f1np1 \
NCCL_SOCKET_IFNAME=enP2p1s0f1np1 \
vllm serve /model/Qwen3.6-35B-A3B-Opus-abliterated-FP8 \
--host 0.0.0.0 --port 30001 \
--gpu-memory-utilization 0.4 \
--max-model-len 262144 \
--max-num-batched-tokens 8192 \
--max-num-seqs 16 \
--enable-prefix-caching \
--enable-chunked-prefill \
--attention-backend flashinfer \
--load-format instanttensor \
--trust-remote-code \
--dtype auto \
--kv-cache-dtype fp8 \
--enable-auto-tool-choice \
--tool-call-parser qwen3_xml \
--reasoning-parser qwen3 \
--tensor-parallel-size 2 \
--distributed-executor-backend ray > /tmp/vllm.log 2>&1"
第五步 — 模型准备(首次部署)
模型路径
模型必须存在于两台机器的 /model/ 目录下,或通过挂载 HF 缓存让 vLLM 自动加载。
Tokenizer 修复(如需要)
cd /home/nvidia/.cache/huggingface/hub/models--*/snapshots/*/
sed -i 's|"tokenizer_class": "TokenizersBackend"|"tokenizer_class": "Qwen2TokenizerFast"|' tokenizer_config.json
模型传输(走 RoCE,比 rsync 快 5 倍)
# 在 102 上监听
ssh user@xxx.xxx.x.102 "nc -l -p 1234 | tar xf -" &
# 在 101 上发送
tar cf - -C /model Qwen3.6-35B-A3B-Opus-abliterated-FP8 | nc xxx.xxx.x.102 1234
💡 说明:Head 加载模型后,Worker 通过 Ray TP 自动同步,Worker 不需要独立模型副本。但如果 HF 缓存不在 Head 上,需要从外部传输。
第六步 — 验证与监控
API 验证
curl http://xxx.xxx.x.102:30001/v1/models | python3 -m json.tool
# 必须返回 {"data": [{"id": "vllm", ...}]}
轻量推理测试
curl http://127.0.0.1:30001/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "vllm", "messages": [{"role": "user", "content": "你好"}], "max_tokens": 50}'
内存监控
watch -n 1 free -h
⚠️ 注意:DGX Spark 统一内存架构下,
nvidia-smi 显示 [N/A] 不可用。如果 swap 超过 8GB,说明 --gpu-memory-utilization 设置过高。
避坑指南
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Gloo 走 127.0.0.1 | GLOO_SOCKET_IFNAME 在 docker exec 中不传递到子进程 | 必须在 docker run -e 级别设置 |
| NCCL 走 TCP 而非 RDMA | 错误设置了 TP_SOCKET_IFNAME 和 NCCL_IB_DISABLE | 绝对不要加这两个参数! 让 NCCL 自动检测 RoCE RDMA |
| fastsafetensors 崩溃 | TP=2 分片时 C++ 解析器确定性崩溃 | 加 --load-format safetensors |
| DGX 内存溢出 | --gpu-memory-utilization > 0.6 | 跨节点 TP=2 固定设为 0.4 |
| 容器找不到模型 | 容器期望 /root/.cache/huggingface/ 但挂载路径不对 | 必须 -v /home/nvidia/.cache/huggingface:/root/.cache/huggingface + TRANSFORMERS_OFFLINE=1 |
⚠️ RDMA 性能关键:不加
TP_SOCKET_IFNAME 和 NCCL_IB_DISABLE,NCCL 自动走 RoCE RDMA(mlx5_2),速度达 68-70 tok/s。加了这两个参数会强制走 TCP,速度仅 ~45 tok/s,性能下降 40%。
参数速查表
| 参数 | 推荐值 | 说明 |
|---|---|---|
--gpu-memory-utilization | 0.4 | 跨节点 TP=2,留更多内存给通信开销 |
--max-num-batched-tokens | 8192 | 跨节点不宜太大,通信开销显著 |
--max-model-len | 262144 | 256K 上下文窗口 |
--load-format | instanttensor | 快速加载 safetensors |
--distributed-executor-backend | ray | 必须用 ray,不用 mp |
--tool-call-parser | qwen3_xml | Qwen3.6 系列工具调用解析器 |
--reasoning-parser | qwen3 | Qwen3 系列推理模式解析器 |
--attention-backend | flashinfer | 性能最佳注意力后端 |
--kv-cache-dtype | fp8 | FP8 KV cache 节省显存 |
--tensor-parallel-size | 2 | 跨节点双卡 TP |
💡 使用建议:并发低、上下文不长时优先单机模式(101 上的 vllm2,端口 30002);仅在大上下文或高并发场景下启用跨节点集群。