我最近被问到最多的一个问题就是就两台机器跑 vLLM到底有没有必要上 Ray问的人多半已经查过资料知道 vLLM 可以在多卡上做张量并行也知道 Ray 能管理分布式集群但就是判断不了这层复杂度值不值得掏。我的答案是大多数两台机器的场景不需要 Ray但如果你要跨节点张量并行或者打算把两台机器做成一个小型推理集群而不是只“跑一个模型”Ray 就成了最值得投入的那部分依赖。要搞明白这件事得先从 vLLM 自己的分布式逻辑说起。1. 两台机器之前先搞懂 vLLM 怎么把模型拆开vLLM 是一个面向 LLM 推理的高性能引擎核心卖点是 PagedAttention 和连续批处理让 GPU 显存和计算效率都能拉满。但模型跑到一定程度单块显卡装不下就需要把模型“拆开”放到多张 GPU 上。拆法不同对通信的要求、对 Ray 的依赖程度也完全不同。1.1 三种并行模式TP、PP、DP 分别解决什么问题vLLM 里最常用的并行方式有三种它们的拆解粒度差别很大模式拆解方式通信频率典型场景Tensor ParallelTP张量并行把一个 Transformer 层的权重按维度切成多份每张卡只算自己那部分而后要做 AllReduce 合并极高每个层都要通信模型单机放不下或者单卡推理太慢需要多卡加速Pipeline ParallelPP流水线并行按层切成几段每张卡负责若干连续的层只往后传激活值和梯度较低每几步通信一次超大模型TP 已经无法横向扩展时Data ParallelDP数据并行每个副本独立跑完整模型不同请求打到不同副本上副本间基本不通信几乎没有模型单副本能放进单卡/单机但要提升吞吐注意这里说的“并行”是模型执行层面的概念和 Ray 没直接关系。vLLM 单实例内部完全可以只用 TP 或 PP不需要任何额外调度器。只有当你把这些并行模式跨机器扩展时才需要考虑谁来协调“哪台机器上的哪张卡参与哪个模型”。1.2 跨节点通信才是真正的分水岭很多人在两台机器上跑 vLLM第一反应是“我要 TP2 跨节点把两张卡拼起来”。这个想法没有错但很容易低估通信瓶颈。TP 的通信模式是每层计算都要做一次 AllReduce。以一个 hidden size 为 8192、batch 为 32 的请求为例光一层要同步的数据量就在 MB 级别模型几十层跑下来跨节点要传的数据量非常可观。同一台机器内部走 NVLink 或 PCIe Switch延迟低、带宽高两台机器之间走的是以太网家庭级万兆网卡实际带宽也就 10Gbps远赶不上 NVLink 的 600GB/s 级别。跨节点 TP 很可能做得出来但速度可能比单机慢得多。PP 的跨节点通信量小一些只传边界上的激活值但它有个天然缺陷流水线气泡。两台机器、两张卡PP2 时一半时间有一张卡在空等。模型非常大的时候可以接受但两台机器跑常见的 7B、14B、32B 模型完全没必要用 PP。另一个特别容易混淆的点是vLLM 的 continuous batching连续批处理是引擎内部的 scheduler 逻辑它负责在同一个实例里动态拼 batch、调度请求优先级这部分根本不依赖 Ray。很多人误以为上了 Ray 推理调度能力就变强了这是错的。Ray 管的是“资源分配”和“多实例编排”不是请求级的排班调度。2. 两台机器部署至少有三种靠谱路径两台机器不等于一定要用 Ray。现实中我见过不少团队本来只想把服务跑起来结果一上来就搭 Ray最后被版本、端口、网络搞到怀疑人生。按我的经验两台机器有下面三条路难度和收益完全不同。2.1 路径 A单机副本 负载均衡最简单也最稳如果模型能放进单台机器的显存里最省事的方案是两台机器各跑一个独立的 vLLM 实例外面加一个 Nginx 或 HAProxy 做负载均衡。这台机器挂了流量自动切到另一台要升级模型也可以一台一台滚更新服务不中断。具体落地很简单。机器 A 和机器 B 上分别起同样的 vLLM 服务vllm serve /models/qwen3-32b \ --tensor-parallel-size 4 \ --host 0.0.0.0 \ --port 8000这里--tensor-parallel-size 4只在单机内做 4 卡 TP没有跨机不需要 Ray。然后在一台前端机器上放一个 Nginx 配置upstream vllm_backend { server machine-a:8000; server machine-b:8000; } server { listen 80; location / { proxy_pass http://vllm_backend; proxy_http_version 1.1; proxy_set_header Connection ; } }这样做的好处两条链路完全独立任意一条挂掉都不影响另一条没有中心节点没有版本同步问题调试的时候直接看单台日志就行。缺点也很明显两台机器各放一个模型副本显存是分开用的模型的总参数不能超过其中一台机器的显存。如果你的模型是 200B单机装不下这条路就直接堵死了。2.2 路径 B跨节点 TP/PPRay 是最省事的“胶水”模型大到单机放不下或者你特别需要单副本的低延迟推理那就只能把模型切到两台机器上一起算。这时 Ray 基本是必须的因为它能把两台机器上的 GPU 统一注册成一个资源池然后给 vLLM 分配一个跨节点的 placement group。启动方式很简单。先在一台机器上起 head 节点ray start --head --port6379 --dashboard-host0.0.0.0另一台机器加入集群ray start --address192.168.1.10:6379用ray status确认两台机器的 GPU 都可见后在 head 机器上起 vLLMvllm serve /models/deepseek_r1_distill_32b \ --tensor-parallel-size 8 \ --distributed-executor-backend ray这里--tensor-parallel-size 8表示把模型切成 8 份分布在两台机器的 8 张卡上。vLLM 看到当前已经有一个 Ray 集群就不会再自己起一套 Ray而是直接复用你手动启动的这个集群。这条路能走通的前提是两台机器之间有足够的网络带宽和尽量低的延迟。如果只是 1Gbps 网卡我劝你放弃跨节点 TP。跨节点 TP 的性能瓶颈几乎全在网络GPU 算得再快数据也传不出去。2.3 路径 C用 Ray 管理多实例、多模型做成小型推理集群还有一种场景你这两台机器不只想跑一个大模型还想同时部署 DeepSeek 推理、Embedding 模型、甚至几个不同尺寸的轻量模型给不同业务方共用。这时 Ray 的真正价值才体现出来。没有 Ray 的时候你得手动规划每张卡给哪个服务端口怎么分配资源不够了怎么办。有了 Ray你可以把资源统一上报然后让 vLLM 的多个实例各自按需申请 GPU。比如一个实例申请 4 张卡跑 DeepSeek另一个实例申请 2 张卡跑qwen3-embedding-0.6b剩下两张卡留着跑 GLM 系列的对话模型。Ray 会保证这些 placement 之间不冲突。这种做法的前提是你已经有“集群化运维”的诉求而不只是“跑一个模型”。如果只是自己测试路径 A 足够路径 C 属于给自己加戏。3. 值得引入 Ray 的五个信号以及不值得的三个信号我在不同场合反复强调一句话架构选型不是技术炫技而是成本收益权衡。引入 Ray 之前先拿下面这张清单对着自己的场景打勾。3.1 值得引入 Ray 的信号第一模型必须跨节点张量并行。单机显存凑不齐只能把模型按层或按权重切开分到两台机器这时候 Ray 是 vLLM 跨节点并行的主流协调方案值得用。第二你需要动态扩缩容。比如白天两台机器都满负荷夜里业务量下降想释放一台机器去跑离线任务。Ray 集群可以随时加节点、减节点vLLM 也会跟着重新调度手动方案做不到这么灵活。第三你要在同一个池子里混合跑多种模型、不同规格的 GPU。两台的 GPU 型号不一样比如一台 A100、一台 L40S手动调度很容易把资源算错Ray 的 resource 声明和 placement group 能精确表达“这个模型必须落在有 A100 的节点上”。第四你把 vLLM 当作一个长期服务而不是一次性的实验。长期服务要考虑故障恢复Ray 可以对任务设置重启策略节点挂了自动把任务拉起来重新调度比你自己写 watchdog 靠谱。第五团队后续一定会扩展到三台、五台机器。与其等到集群大了再迁移不如在最开始就把调度层做好。两台机器的 Ray 集群和二十台机器的 Ray 集群概念上完全一样越早统一越省事。3.2 不值得引入 Ray 的信号反过来如果命中下面几条Ray 就不是“值得”而是“没必要”信号解释更优方案只跑一个模型且单机能放下Ray 解决不了推理速度只会增加更多进程和端口要维护单机两副本 负载均衡两台机器之间只有 1Gbps 网卡跨节点 TP 通信会把性能拖垮Ray 救不了每台各跑一个副本做 DP目标是快速验证模型效果安装 Ray、配置集群、调网络都是额外负担直接单机vllm serve一条命令跑起来模型小到像 0.6B 的 embedding 模型一张卡轻松放下用 TP 都浪费更别提跨机直接单实例部署端口暴露出去就行我见过不少团队两台 8 卡机器跑 7B 模型非要套 Ray最后因为 Ray 版本和 vLLM 不兼容折腾了两天才发现直接单机双副本更符合需求。这不是 Ray 的问题是需求判断出了问题。4. 上 Ray 之后的隐形成本每个都是实操里踩过的坑Ray 不是坏东西但它有实打实的隐形成本。下面这几个点是我在真实项目里踩过、也帮别人排查过的坑。4.1 版本兼容性是第一道鬼门关vLLM 官方 Docker 镜像自带特定版本的 Ray比如你拉vllm/vllm-openai:v0.27.1这个镜像里面的 Ray 版本是固定的。如果你想要让它接入一个外部已经运行的 Ray 集群而这个集群 head 节点的 Ray 版本和镜像里的版本不一致连上的瞬间就会报一堆莫名其妙的任务错误日志里带一长串ray id: xxxx真正有用的信息反而被淹没在末尾。我的处理习惯是要么完全不用外部 Ray让 vLLM 自己启动它内置的 Ray要么就让所有节点、所有容器都用同一个 vLLM 镜像从根源上避免版本漂移。因为 Ray 官方一直强调 head 和 worker 版本必须严格一致小版本不一致也可能出事。4.2 Docker 容器里 Ray 经常看不到 GPU容器里跑 vLLM 是常态但很多人忽略了一件事Ray 在容器里默认看不到 GPU除非你把 NVIDIA 的 runtime 和设备都正确暴露给容器。典型表现是ray status显示的 GPU 数是 0但容器里nvidia-smi明明能看到卡。这个问题通常出在 Docker 启动参数上。要么你在docker run时漏了--gpus all要么没有用nvidia-container-toolkit配置默认 runtime。还有一个小技巧给容器加--ipc host因为 NCCL 和 Ray 的共享内存机制都依赖/dev/shm容器默认的 64MB 共享内存会在模型加载时直接报“bus error”或者“waiting for all workers”卡死。4.3 网络性能决定跨节点 TP 的生死我在 10GbE 的两台机器上跨节点 TP8 跑过 72B 模型吞吐只有预期的一半多一点。后来用iperf3测了一下TCP 实际吞吐只有 7Gbps 左右而 NCCL 用 TCP 做 AllReduce效果远不如 RDMA。这个问题不是 Ray 能解决的是物理网络决定的。所以现在我的建议是在上跨节点 TP 之前先做两个测试。第一用iperf3 -s和iperf3 -c ip测带宽第二在小模型上跑一次 TP2 跨节点推理对比单机 TP2 的速度如果差距超过 30%就别硬上跨机了。要不就换 DP每个副本单独服务两边互不通信网络压力小得多。4.4 小模型走上 Ray 就是典型过度设计比如qwen3-embedding-0.6b这种 6 亿参数的 Embedding 模型单卡显存占用不到 2GB完全不需要分布式。我见过有人把它也放到 Ray 集群里跑理由是“统一管理”。结果模型部署没问题但每次调用都要经过 Ray 的对象传输延迟硬生生多出几毫秒。为了“统一管理”牺牲核心路径性能不值得。Embedding 模型的最佳实践就是单实例部署甚至可以直接用 CPU 跑根本不需要 GPU。同样很多 GLM 系列的小对话模型也是类似逻辑先想清楚模型大小再决定要不要上调度框架。搜索热词里那么多“GLM5.3 用哪个 vLLM 镜像版本”的问题本质上也是在问“这个模型怎么部署最简单”而不是“我要不要上一整套 Ray”。5. 实操记录两台机器从零起 Ray 并跨机跑 DeepSeek下面给你一份可以直接抄的实操步骤场景是两台 8 卡机器跑一个单机放不下的 DeepSeek 蒸馏版模型目标是把 16 张卡合成一个模型并行空间。5.1 第一步确认硬件和网络先在两台机器上都装好 Ray 和 vLLM。建议直接用官方 Docker 镜像省去编译和依赖问题。分别执行docker pull vllm/vllm-openai:v0.27.1然后确认两台机器能互通# 在 head 机器上 iperf3 -s # 在 worker 机器上 iperf3 -c 192.168.1.10如果带宽低于 10Gbps建议就此打住考虑 DP 双副本方案。5.2 第二步启动 Ray 集群Docker 方式在 head 机器上docker run --rm --network host --ipc host \ --gpus all \ -e NVIDIA_VISIBLE_DEVICESall \ -v /models:/models \ vllm/vllm-openai:v0.27.1 \ ray start --head --port6379 --dashboard-host0.0.0.0注意这里必须加--network host不然容器里的 Ray 无法让 worker 节点通过宿主机 IP 访问。在 worker 机器上docker run --rm --network host --ipc host \ --gpus all \ -e NVIDIA_VISIBLE_DEVICESall \ -v /models:/models \ vllm/vllm-openai:v0.27.1 \ ray start --address192.168.1.10:6379启动完成后在 head 容器里执行ray status正常会看到两行 Node每行后面跟着 8 个 GPU。5.3 第三步启动跨节点 vLLM在 head 机器上另起一个容器复用同一个镜像和网络执行docker run -d --name vllm-deepseek \ --network host --ipc host \ --gpus all \ -e NCCL_DEBUGINFO \ -e NCCL_IB_DISABLE1 \ -v /models:/models \ vllm/vllm-openai:v0.27.1 \ vllm serve /models/deepseek_r1_distill_72b \ --tensor-parallel-size 16 \ --distributed-executor-backend ray \ --port 8000这里--tensor-parallel-size 16表示 16 张卡一起做张量并行。NCCL_DEBUGINFO是为了让你第一次调试时能看到实际的通信路径确认走的是 TCP 还是 Infiniband。确认正常后可以去掉这个环境变量减少日志刷屏。模型加载日志里会看到类似 “Ray worker 0-15 registered” 这样的内容说明跨节点并行已经建立。5.4 第四步验证和排错启动后用 OpenAI 兼容接口测一下curl http://localhost:8000/v1/models然后让 Chatbox 之类的客户端直接填http://192.168.1.10:8000/v1模型名填日志里显示的 checkpoint 名字就能正常对话了。如果客户端一直连不上先确认是不是路径问题vLLM 的 OpenAI 兼容端点一定在/v1下不是根路径。首次跨节点 TP 大概率会遇到通信慢、卡加载等问题。这时候不要慌按下面的顺序排查先看ray status是否所有 GPU 都 ready再看NCCL_DEBUGINFO日志里有没有 TCP 连接失败最后用iperf3重测带宽。绝大多数问题都出在网络而不是 Ray 本身。6. 常见问题排查速查表我把实操里高频出现的问题做成一张表遇到直接对着查现象可能原因处理方式ray.exceptions.RayTaskError或连接超时带一串ray idhead 地址配错、防火墙挡了 6379/8265 端口、Ray 版本不一致先ray status看集群状态检查两台机器的防火墙和安全组确认镜像内 Ray 版本和 head 一致容器内ray status显示 GPU 数为 0没开--gpus all或 nvidia-container-toolkit 未生效检查nvidia-smi是否可见重启容器加上--gpus all确认 Docker 默认 runtime 是 nvidiavLLM 卡在waiting for all workers容器共享内存太小或跨节点 NCCL 连不上加--ipc host检查宿主机/dev/shm大小临时设NCCL_P2P_DISABLE1排除通讯问题跨节点 TP 推理速度比单机还慢网络带宽不足或延迟过高用iperf3测速改为双实例 DP各跑一个副本vLLM 启动时报模型不受支持镜像版本太老不支持新模型架构去 vLLM release notes 搜模型名换用最早支持该模型的新 tag 镜像用 vLLM 加载qwen3-embedding-0.6b报错Embedding 模型对 vLLM 版本有额外要求确认用--task embed参数或换专用向量服务不要强行塞进推理引擎踩过几次坑之后我对“两台机器跑 vLLM 要不要上 Ray”这个问题已经有了一套很顺的判断逻辑模型能单机放下就绝不碰 Ray模型必须跨节点就老老实实把 Ray 版本和网络调好有平台化夙愿就尽早统一成 Ray 集群但时刻记住 Ray 是资源调度器不是推理加速器。最后再分享一个小技巧如果你最终决定不上 Ray只是两台机器各跑一个副本做负载均衡记得给两个实例设置不同的model名称前缀或者在 Nginx 里加一个X-Server响应头。不然出了问题你根本不知道当前请求落到了哪台机器上排查会非常痛苦。