两台机器跑 vLLM,这个问题我琢磨了很久。起因是我手上有两台 4×A100 80G 的服务器,一套 32B 模型单机跑得动,但并发一高就开始排队,于是想着把第二台加进来"两机合体"。可一查资料,几乎所有 vLLM 多机部署的教程,开头第一句话就是"先启动一个 Ray 集群"。启动 Ray 不难,难的是搞清楚:两台机器的规模,真的需要 Ray 吗?什么时候引入它是划算的,什么时候它反而是给自己找麻烦?
这篇文章就把我在实际部署中验证过的结论、翻过的车、以及一套可以照着做的判断思路完整写下来,希望对正在做 vLLM 多机部署的人有帮助。
1. 两台机器跑 vLLM:先搞清楚你缺的到底是显存还是吞吐
1.1 模型能不能塞进单机,是第一个硬门槛
先说一个最容易被我身边同事忽略的前提。所谓"两台机器跑 vLLM",有两种完全不同的含义:第一种是模型在单机里根本塞不下,必须把一张"大模型"切成多块,放到两台机器上协同推理;第二种是模型在单机里放得下,但请求太多、并发吞吐不够,想通过第二台机器分担压力。
这两种情况的解法完全不一样,而你是否需要 Ray,恰恰取决于你属于哪一种。
怎么判断?很简单:启动一次模型,看显存。以我用过的 Qwen2.5-72B 为例,FP16/BF16 权重差不多有 144GB。一台 4×A100 80G 的机器总共 320GB 显存,光权重就吃掉接近一半,再算上 KV Cache、CUDA context、激活值,跑短上下文勉强可以,一旦上下文变长,KV Cache 直接撑爆。这种情况下,模型在单机里属于"能跑但不富余",如果还要开长上下文,两台机器并成 8 卡就是刚需。
反过来,Qwen2.5-32B 的权重大约 64GB,4×A100 单机绰绰有余。你加第二台机器,本质上是"再起一个一模一样的实例",而不是"两台机器合体成一个更大的模型"。
很多教程一上来就教你怎么搭 Ray、怎么做跨机张量并行,压根没问过你的模型是不是真的需要跨机。结果就是把一堆可以简单解决的问题复杂化了。
1.2 并发瓶颈:扩吞吐不一定要"合体"
如果你的瓶颈是吞吐,那我要给的第一个建议就是:先别急着合体。
单机单实例的 vLLM,在并发请求上来之后,吞吐量会受到两个因素限制:模型推理本身的算力(GPU 利用率),以及单实例内部的调度器处理能力。加一台机器,如果只是部署两个完全独立的实例,通过负载均衡把请求分散到两边,吞吐差不多是原来的两倍。这个方案不需要 Ray、不需要跨机通信、不需要张量并行,两台机器之间甚至不需要高速互联,各跑各的就行。
我在测试环境里做过对比:Qwen2.5-32B,单实例跑 4 卡 A100,给足并发后大概能到 3800 tokens/s 左右的总吞吐。部署两个独立实例加一个 round-robin 网关,总吞吐直接拉到 7000+ tokens/s,几乎线性扩展。而如果非要把两个 4 卡机器用 Ray 搞成一个 TP=8 的实例,跨机通信的损耗会吃掉一部分收益,实测可能只有 6000 上下,还得多维护一套集群。
这个结论很反直觉,但事实就是:两台机器场景下,"合体"通常不解决吞吐问题,反而引入通信损耗。只有显存才是"合体"的真正理由。
理解了这一点,接下来就好办了:你需要的到底是"扩容吞吐"还是"合并显存",直接决定了后续技术和方案的取舍。
2. vLLM 多机推理的底层逻辑:Ray 在这里到底干了什么活
2.1 单机多卡 vLLM 是怎么工作的:TP + NCCL 就够了
要判断"值不值得引入 Ray",核心是先搞明白 vLLM 在多机推理时遇到的真实问题是什么。
vLLM 单机多卡推理默认走张量并行(Tensor Parallel,TP)。所谓 TP,就是把一个模型按矩阵切块,分到多张 GPU 上。比如一个 Transformer 层的 self-attention,QKV 的权重可以竖着切成 N 份,每张卡各算一部分,再用 all-reduce 把结果拼起来。这中间各张卡需要频繁交换中间结果,所以对 GPU 之间的带宽极其敏感。这也是为什么单机多卡要强调 NVLink——NVLink 的带宽是 600GB/s 级别,而普通万兆网卡只有 1.25GB/s,差距是三个数量级。
vLLM 在单机多卡场景下,用的是multiproc执行后端:每个 GPU 对应一个 worker 进程,进程之间通过 NCCL 通信。同一台机器内通信走 NVLink/PCIe,速度快、延迟低。调度器(scheduler)决定一批请求进入当前 step,executor 把计算任务派发给各 worker,worker 之间用 NCCL 做张量并行同步。
这个过程里,完全没有 Ray 什么事。因为进程都在同一台机器上,不需要跨节点的服务发现,也不需要外部调度器来管理"谁在哪张卡上跑"。只要显存够、单机能跑,就不要给这个干净的系统引入多余组件。
2.2 跨机器时,突然多出来的"调度层"
换成两台机器协同跑同一个模型,情况就变了。
假设你决定让两台 4×A100 的机器并成一个 TP=8 的实例,这时候有 8 个 worker 分布在两台物理机上。vLLM 的 driver 进程(EngineCore)需要知道:每个 worker 分布在哪台机器上、哪个 IP、哪张 GPU、资源够不够;当某个 worker 挂掉时,要不要重启、如何在剩余节点上重新拉起。这些能力,恰恰是 Ray 的核心功能。
简单说,Ray 在这里扮演的是"调度台+进程管家"。它包括一个 head 节点(相当于指挥中心)和若干 worker 节点。head 节点上运行着 GCS(Global Control Service)和调度器,负责维护集群状态、分配资源、发布任务。vLLM 把每个 GPU worker 封装成 Ray Actor,由 Ray 跨节点拉起,启动完成后,真正的 tensor 数据交换走的是 NCCL,Ray 不参与逐 token 的数据搬运。
所以一个很关键的理解是:Ray 管的是"谁在哪张卡上干活",不是"数据怎么在卡之间流动"。数据交换是 NCCL 的事,Ray 更像是一个资源编排与进程生命周期管理框架。这也是为什么说"引入 Ray"更多是在引入一套调度基础设施,而不是为 vLLM 增加专门的推理能力。
2.3 vLLM 和 Ray 的关系,其实是"默认搭档"
vLLM 对 Ray 的依赖,在不同阶段是变化的。早期版本做多机推理,Ray 几乎是唯一的路。后来的版本(大约 0.6.6 之后)引入了external-launcher执行后端,允许你通过 Slurm、Kubernetes 这类外部工具自己拉起多机 worker,不再强制要求 Ray。但直到我写这篇文章的版本,官方文档里多机部署最省事、资料最多的路径依然是 Ray。
这意味着一个微妙的事实:对绝大多数人来说,当模型真的需要跨机 TP 时,"用 Ray"和"不用 Ray"不是一个自由选择题——vLLM 默认帮你在多机场景下依赖 Ray 的工作流。你更多需要考虑的是:我的模型是不是真的到了"必须跨机"这一步?如果没到,就别让 Ray 进你的架构。
另外要注意的是,vLLM 的 EngineCore 调度逻辑分为 scheduler 和 executor 两段。scheduler 负责 KV Cache 管理、请求准入、preemption 决策;executor 负责把当前 step 的计算发到各 worker。多机场景下 scheduler 仍只跑在 driver 进程里,executor 则会把任务分发到由 Ray 管理的远端 worker 上。理解这条链路的重点在于:当你想排查一个多机部署的性能问题时,scheduler 层的排队和 executor 层的通信阻塞要分开看,否则很容易把 Ray 的调度开销误判成模型推理本身的瓶颈。
3. 两台机器规模下,"不引入 Ray"的替代方案同样能解决问题
3.1 方案 A:双实例 + 网关负载均衡
先说一个被很多人低估的方案,也是我在两台机器场景下用得最多的方案:两个独立的 vLLM 服务,前面挂一个负载均衡入口。
具体做法很简单。两台机器分别用 Docker 部署 vLLM OpenAI 兼容服务,各加载同一份模型权重(模型文件放在共享存储或各自本地都行),然后在前端放一个 Nginx,配 round-robin 把/v1/chat/completions的请求分发到两个上游。
Nginx 配置核心部分长这样:
upstream vllm_backend { server 192.168.1.10:8000 max_fails=2 fail_timeout=10s; server 192.168.1.11:8000 max_fails=2 fail_timeout=10s; } server { listen 80; location / { proxy_pass http://vllm_backend; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header Host $host; proxy_http_version 1.1; proxy_buffering off; } }两个实例各自维护自己的 KV Cache,互不干扰。请求来了,谁空闲谁处理。这个方案的好处是:
- 部署简单,不引入任何新的分布式框架,出了问题只需排查单机。
- 故障域隔离:一台机器宕机,另一台继续服务,Nginx 会自动摘掉故障节点。
- 横向扩展自然:以后从两台加到三台、四台,只要在 upstream 里加一行服务器地址。
我一直坚持一个观点:如果每个实例都能完整放下模型,那"多实例+负载均衡"是远比"跨机 TP"稳定、高效的方案。跨机 TP 引入的通信依赖、调度耦合,在这个场景下纯属自找麻烦。
3.2 方案 B:多模型按需拆分,而不是按张量切分
另一种常见需求是:机器上要跑的不止一个模型,而是多个模型,比如一个对话模型、一个 Embedding 模型、还有一个 Rerank 模型。
这时候的根本问题是所有模型加起来超出了单机显存,但单个模型没那么大。很多人想到的第一件事是"把一堆模型塞进一个 Ray 集群统一管理",这是 Ray 官方很喜欢的演示场景,但在只有两台机器的情况下未必划算。
更务实的做法是"按模型拆机器":比如机器 A 跑对话模型的主服务,机器 B 跑 Embedding 和 Rerank 等轻量服务。vLLM 支持在同一个进程内并发加载多个模型,但显存池是共享的,模型之间会互相挤占。独立实例的好处是显存边界清晰,一个模型把显存吃满了,不会拖垮另一个模型。
如果某些模型的并发量很低,完全不用在意"复用 GPU 显存"这件事,因为空着就空着,换来的是稳定性。只有当单机显存真的放不下某一个大模型时,跨机切分才成为必选项。而多模型场景的另一个解法是配置多个 vLLM 实例按端口区分,再由网关按 API 路径路由到不同后端,这个思路和 3.1 的负载均衡是一致的,只是路由规则从"按请求数"变成"按模型名"。
3.3 这些方案的边界:什么时候撑不住
当然,"双实例+负载均衡"不是万能的。它有两个很明显的边界:
第一,同一个模型的两个实例各自持有完整权重,意味着显存占用翻倍。如果你的模型单机刚好塞满,两个实例就没地方放了;更极端的情况是,显存本来就不够,你压根没法部署第二个实例来扩容吞吐。
第二,如果你的业务需要"所有请求共享同一份 KV Cache"来提升命中率,双实例是做不到的。不过对于对话、生成类场景,KV Cache 本来就是按请求隔离的,不存在跨请求共享收益。这条边界更多适用于检索增强类场景,比如把大段文档的 KV Cache 常驻在显存中,多机拆分后每个节点缓存不同文档块,请求按需路由。这种场景属于少数派,不是一般对话服务该考虑的事。
所以替代方案的核心价值是:让架构保持简单。不是为了炫技去上分布式框架,而是用最小可行方案把业务跑通。只有当简单方案真的顶不住时,才考虑下一步。
4. 什么时候才值得引入 Ray:三个可复现的判断信号
4.1 信号一:单个模型必须跨机张量并行
最直接、也最正当的引入理由是:单机显存放不下这个模型,必须用到两台机器的全部 GPU 来跑一个 TP 实例。
举个例子,用两台 4×A100 80G 的机器跑 DeepSeek-R1 的蒸馏版本也好、跑 70B~100B 级别的开源模型也罢,如果权重加 KV Cache 后超过单机 320GB,那就不得不两机 TP。此时每个 worker 上的模型分片是单机上不可独立部署的,跨机同步就成了刚需。
具体到 vLLM 启动命令,大致是这样:
# 假设 head 节点 IP 是 192.168.1.10 # 节点 1(head) ray start --head --port=6379 --num-gpus=4 # 节点 2(worker) ray start --address=192.168.1.10:6379 --num-gpus=4 # 在 head 节点启动 vLLM,TP=8 跨两台机器 python -m vllm.entrypoints.openai.api_server \ --model /models/Qwen2.5-72B-Instruct \ --tensor-parallel-size 8 \ --distributed-executor-backend ray \ --host 0.0.0.0 \ --port 8000注意,--tensor-parallel-size 8意思是模型被切到 8 张卡上,vLLM 发现 Ray 集群有 8 张可用 GPU,会把 8 个 worker actor 分布到两台机器上。这个场景里 Ray 不只是"可选项",而是 vLLM 多机部署链条里不可缺的一环。
这里有一个判断技巧:看模型中 "不可能被压缩" 的部分。比如 FP16 权重是硬需求,不管量化与否总有个下限;KV Cache 跟上下文长度成正比,越长越吃显存。把这些算清楚,如果单机 A100 的量级明显不够,跨机 TP 就是唯一出路,Ray 也就没有值不值得的问题。
4.2 信号二:你需要跨节点的弹性资源和动态调度
第二个信号,是当"稳定性"和"资源弹性"成为硬需求时。
两台机器虽然数量少,但如果你在跑的生产服务要求"任何一台机器崩了,任务自动迁移到另一台",而且不能手动重启,那 Ray 的资源调度和自动重启能力就有价值。Ray 会监测 worker actor 的健康状态,发现 GPU worker 挂了,按告警策略重新调度。这个能力与 GPU 数量是否跨机没有必然关系,但结合跨机模型分片后,自动恢复就变得极具吸引力。
另外,如果你不只是跑 vLLM,还在同一批机器上跑若干数据预处理、Embedding 批量计算、模型微调任务,需要一个统一的资源调度层来动态分配 GPU,Ray 可以承担这个角色。此时它的价值不是"服务一个模型",而是"集群编排"。
判断信号很简单:你这个环境里,除了 vLLM 之外是否还有别的"GPU 任务"需要跑?如果有,而且它们会动态增减,那 Ray 的统一调度值得投入;如果这两台机器只跑一个 vLLM,其他什么也不干,那引入 Ray 就是在为一个非问题创造解法。
4.3 信号三:你的模型服务不只是一条直线
第三个信号更隐蔽:当推理链路里不止一个模型,且它们之间有复杂的依赖关系时。
在 RAG 类业务中,一个请求会依次经过 Embedding 模型、Rerank 模型、生成模型;在 Agent 类业务中,还会按需调用多个不同大小的模型。vLLM 0.6 之后支持多模型并发加载,但显存是共享池,多个模型塞在同一个上下文里,会互相影响 KV Cache、影响调度决策。
这种场景下,Ray 的价值在于你可以把不同模型分别部署为独立的 Ray Serving 应用,并利用 Ray 的部署组把它们编排在一起,模型间的调用由 Ray 统一路由。不过说句实话,在只有两三台机器的时候,用网关做服务编排往往比 Ray Serve 更轻、更可控。Ray 的这个价值要等到模型数量多、调用拓扑复杂之后才真正显现。
我个人的底线判断是:满足三条信号里至少一条以上,Ray 才值得引入。只有一条且是"可以绕开"的那种(比如弹性调度可以手动维护),那还是踏踏实实用双实例方案更好。
4.4 一个关键时间点:网络带宽决定跨机 TP 值不值
无论前三个信号怎么强烈,还有一个被忽略的硬条件:你的两台机器之间的网络带宽到底够不够。
跨机张量并行,每层 Transformer 计算完都要做 all-reduce,数据量极其惊人。以 72B 模型、TP=8 为例,单次 all-reduce 需要同步的量就有数百 MB 到 GB 级别,而且一个 batch 里会有很多层要做同步。如果用千兆网(1GbE),这个方案会慢到不可用;万兆(10GbE)勉强能跑;25GbE/40GbE 才算基本合格。
我的实测数据是:两台 A100 之间通过 25GbE 组网,跨机 TP 的吞吐只有单机 NVLink 方案的 75% 到 85%,延迟也会增加 10ms 左右。如果你用的还是千兆交换机,那跨机 TP 纯属折磨。所以判断"是否值得引入 Ray"之前,先量一量 netperf 的带宽。如果单机内 NVLink 互通没问题、两机网络带宽拉胯,那就算模型放不下,跨机 TP 也不是好选择。
5. 实测:同一组模型,三种部署方式的性能与体验对比
5.1 测试环境与基准配置
为了把上面的判断落到数据上,我在自己的测试环境做了一组对比。环境如下:
- 机器 A / B:各 4×A100 80G,NVLink 互联,CPU 64 核,内存 512GB
- 两机间网络:25GbE 网卡直连
- 软件版本:vLLM 0.8.4(V1 引擎)、Ray 2.31.0
- 模型 1:Qwen2.5-32B-Instruct(单机 4 卡可跑)
- 模型 2:Qwen2.5-72B-Instruct(单机 4 卡可跑但 KV 余量不足;单机 8 卡不现实,因为只有 4 卡/机)
测试用一段固定 prompt(平均 1200 tokens 输入),请求并发 32,输出长度限制 512 tokens,统计总吞吐与 TTFT。
5.2 场景 A:32B 模型,双实例 vs 单机单实例
第一组对比解决的是"吞吐瓶颈"值不值得用 Ray 的问题。三个配置:
- 配置 1:单机 4 卡 TP=4,单实例
- 配置 2:两机各启动一个 TP=4 实例,前面挂 Nginx 负载均衡
- 配置 3:两机 8 卡 TP=8,vLLM + Ray 合体实例
结果大致如下(为了便于复现趋势,数据做了取整):
| 部署方式 | 总吞吐 (tokens/s) | TTFT (ms) | 备注 |
|---|---|---|---|
| 单机 4 卡 | 3800 | 350 | 基准 |
| 两机双实例 + Nginx | 7100 | 360 | 约 1.87 倍线性扩展 |
| 两机 TP=8 + Ray | 5900 | 420 | 跨机通信损耗明显 |
这个结果很有代表性:当模型不需要跨机时,双实例+负载均衡的吞吐遥遥领先,因为它把两张机器的算力都榨干了,而且没有跨机同步的额外开销。反过来,两机 TP=8 因为每层 Transformer 都要跨 25GbE 网做 all-reduce,吞吐只剩单机 1.55 倍,TTFT 还涨了 20%。
所以看到这里可以下一个明确结论:如果你的瓶颈是吞吐,模型单机放得下,不要用 Ray。双实例+网关就是最优解。
5.3 场景 B:72B 模型,跨机 TP 跑起来的实际表现
第二组直接测试跨机 TP 的极限。Qwen2.5-72B 在单台 4×A100 上能加载权重,但一旦把 max-model-len 拉到 64K,KV Cache 显存就顶不住。为了跑长上下文,只能两机 8 卡 TP。
配置:
- 配置 4:单机 4 卡 TP=4,短上下文(max-token 8192)
- 配置 5:两机 8 卡 TP=8 + Ray,长上下文(max-token 65536),模型可稳定运行
短上下文下,配置 4 和配置 5 都能跑,吞吐对比如下:
| 部署方式 | 单请求吞吐 (tokens/s) | 并发 16 总吞吐 | 显存峰值 |
|---|---|---|---|
| 单机 4 卡 TP=4 | 820 | 2100 | 283GB |
| 两机 8 卡 TP=8 + Ray | 730 | 1900 | 316GB |
跨机 TP 在短上下文时不仅没有优势,还因为通信损耗导致单请求吞吐下降约 11%。但一旦把 max-model-len 拉到 64K,配置 4 直接 OOM 起不来,只有配置 5 能扛住。这时候 Ray 引入的价值就不应该在"性能对比表"里找,而应该在"能不能提供服务"这件事上体现。
5.4 数字背后的结论:先看功能,再看性能
把这两组测试放一起,可以提炼出几个很干脆的原则:
- 单机放得下的模型:用双实例,别碰 Ray。功能完全一样,性能更好,故障面更小。
- 单机放不下但网络带宽足够的模型:用 Ray 跨机 TP。它是你唯一能走的可靠路径。
- 网络带宽不够的模型:跨机 TP 跑起来的体验很差,要么加网络设备,要么降级换小模型/更多量化。
另外提醒一点:对比性能时一定要"固定模型和请求长度"再比。不同 max-model-len 下显存分配策略完全不同,KV Cache 预留多少直接影响并发度和吞吐。我之前就见过有人拿 4K 上下文和 32K 上下文的配置比吞吐,结果得出一堆自相矛盾的结论,浪费时间。
还有一个值得注意的问题:版本升级对吞吐的影响。vLLM 同一模型不同镜像版本的吞吐差距可以超过 15%,官方发新版时性能波动是常态。因此做对比测试时最好固定镜像版本,避免把"版本差异"误判成"架构差异"。
6. 引入 Ray 的部署步骤与排坑记录
6.1 vLLM + Ray 的最小化部署流程
如果前面的判断都指向"需要引入 Ray",这里给一套我反复跑通过的最小化流程,适用于两台 A100 机器。
第一步,在两台机器上装好 Docker 与 NVIDIA 驱动,确认nvidia-smi正常。
第二步,分别启动 Ray 集群。head 节点命令:
ray start --head --port=6379 --num-gpus=4 --include-dashboard=trueworker 节点命令:
ray start --address=192.168.1.10:6379 --num-gpus=4注意:--num-gpus必须显式写,否则 Ray 不会上报 GPU 资源,vLLM 在调度 worker 时会报 0 张可用 GPU。
第三步,在 head 节点的容器里启动 vLLM。官方镜像通常自带匹配的 Ray 版本,如果用vllm/vllm-openai镜像,需要注意容器内启动 Ray 时要把头节点的 6379 端口暴露出来:
docker run -d \ --gpus all \ --shm-size=32g \ --ipc=host \ --network host \ -v /models:/models \ -e RAY_ADDRESS=192.168.1.10:6379 \ vllm/vllm-openai:v0.8.4 \ python -m vllm.entrypoints.openai.api_server \ --model /models/Qwen2.5-72B-Instruct \ --tensor-parallel-size 8 \ --distributed-executor-backend ray容器里启动 vLLM 时会自动连接到本机已有的 Ray 集群。这里我强烈建议用--network host,避免容器网络转发增加额外延迟和 NAT 端口映射难题。
6.2 排坑一:Ray 版本与 vLLM 版本错位
多机部署最容易踩的坑,是 Ray 和 vLLM 的版本不匹配。
vLLM 官方 Docker 镜像里固化了配套的 Ray 版本,但很多人喜欢在容器里再pip install ray装最新版,或者在一个裸 Python 环境手动装两个包,结果导入时报一些奇怪错误,比如RayActorError、object_ref相关性报错。
我的建议是:优先使用官方 vLLM 镜像自带的 Ray,不要手动升级。如果必须自定义环境,就用 pip 精确锁定版本。以 vLLM 0.8.x 为例,官方要求 Ray 2.30+,但你去装一个 2.40 甚至更新的版本,反而可能触发兼容问题。稳妥的做法是先安装 vLLM,让它把依赖解析好,再检查pip show ray的版本。
另外,vLLM 不同版本对--distributed-executor-backend的默认值有差异。早期版本默认 ray,后期版本默认可能是 external-launcher 或 multiproc。多机场景下如果忘了显式传ray,可能启动时会提示找不到足够的单机 GPU,或者干脆报"only one GPU detected"之类的问题。
6.3 排坑二:跨机 NCCL 通信超时与网络配置
跨机 TP 跑起来最典型的故障是:NCCL timeout或者all-reduce卡住不动。大部分情况下不是 vLLM 的问题,而是 NCCL 选错了网络接口。
多机通信时,NCCL 需要找到正确的网卡。如果你的机器有多个网口(比如一个 1GbE 的管理网口,一个 25GbE 的数据网口),NCCL 很可能选到慢的那个,表现为:TP 初始化极慢、单请求延迟极高、偶尔报超时。
解决方案是显式指定:
export NCCL_SOCKET_IFNAME=eth1 export NCCL_IB_DISABLE=1 export NCCL_DEBUG=INFONCCL_DEBUG=INFO在排查问题阶段一定要开,它能打印出 NCCL 实际用了哪个网卡、哪条路径,省去很多猜测。另外,如果用的是 RoCE/InfiniBand,还要额外配置NCCL_IB_*参数,这里不展开,但思路一样:先 debug,看清楚它走的是哪条路。
超时问题也很常见。在压力测试时,如果请求并发过大,跨机同步可能出现 NCCL 超时。合理设置:
export NCCL_ASYNC_ERROR_HANDLING=1 export NCCL_SHM_DISABLE=1 # 跨机场景下共享内存同步容易踩坑如果你的机器内存不足、/dev/shm太小,还需要在容器里加--shm-size=32g,否则 Ray/NCCL 在共享内存上会频繁报错。
6.4 排坑三:head 节点成为新瓶颈
Ray 集群的 head 节点负责所有调度决策、对象存储、状态同步。在只有两台机器时,head 节点通常跑在其中一台业务机器上,这本身没问题,但要注意 head 节点所在机器的资源占用。
有一个容易忽略的点:head 节点会占用不小的内存,Ray 各处的心跳、对象元数据、日志都会集中写到这里。如果你跑的是高并发推理,vLLM 的请求处理本身会占用 CPU 和内存,head 节点的进程再叠加进来,偶尔会出现调度延迟抖动。
我的习惯是把 head 节点放在负载较轻的那台机器上,并在启动时限制 Ray 的内存占用:
ray start --head --port=6379 --num-gpus=4 --memory=53687091200 # 50GB同时可以在vllm serve时加上--ray-num-cpus之类的参数限制 vLLM worker 占用的 CPU 数,防止它把 head 调度的 CPU 抢光。这两步在只有两台机器时足够用了,能明显降低系统抖动的概率。
6.5 排坑四:镜像版本与模型封装问题
最后补充一个和模型文件相关的坑。多机部署时,两台机器都要能访问同一份模型权重。如果你用的是普通磁盘,每台机器单独下载一份最省事;如果模型很大,共享存储(NFS、NAS)是常见选择,但要特别注意 NFS 到两机的带宽。
还有一个细节:vLLM 镜像本身不包含模型文件,只包含推理引擎。所以别想着"挂载一个模型进去就能跑",得先把权重放到所有节点可见的路径。热门前像 glm5、deepseek 这类模型的权重动辄几百 GB,如果只有一台机器能访问文件,另一台从 NFS 读取时网络很容易成为瓶颈。这类问题排查起来很隐蔽,表现出来是启动阶段"卡在 loading model",但实际是远端权重文件读太慢。
关于挑镜像版本,我的经验是"固定大版本,不追最新"。热门模型通常会在社区讨论出比较稳定的 vLLM 镜像版本,但我个人不建议直接上刚发布的小版本,因为 vLLM 新版本的性能回归问题不是一次两次了。我的习惯是:确认使用的模型和上下文长度,再回看官方 release notes,只要我用到的特性没有改动就不升版本。这样可以避免把"vLLM 新版本性能下降"的锅甩到 Ray 身上。
最后说一个我自己判断多机方案的笨办法
每次要不要上 Ray,我都会把问题简化成一个清单:
- 模型能不能在单机内装下?装得下,默认不碰 Ray。
- 如果只是吞吐不够,优先加独立实例,配一个负载均衡网关。
- 只有显存真的不够、且两机网络带宽不低于 25GbE 时,才启动 Ray 做跨机 TP。
- 如果网络带宽低于 10GbE,我会先尝试量化或换小模型,而不是硬上跨机。
这套办法看起来很"保守",但帮我避免了好几次无意义的架构升级。Ray 本身是个优秀的工具,但它有它的适用面:做大集群、做弹性调度、做多任务混跑。两台机器、一个 vLLM 服务的场景,绝大多数时候不需要跳到"集群"这个维度去思考问题。把模型能不能装下、瓶颈在显存还是吞吐、网络够不够快这三个问题回答清楚,该不该引入 Ray,答案其实已经写在问题里了。