Ray/KubeRay 与拓扑约束:从单卡到多节点

草稿

资源数量易得,资源位置难控。多节点 GPU 平台的核心挑战,是让“可调度”真正等于“可用”。

单卡阶段,讨论“共享/隔离”时,很多经验默认了一个前提:瓶颈主要在 GPU 本身与显存。一旦进入多卡、多节点,瓶颈会迅速外溢到 NUMA、PCIe/NVLink、NIC/交换网络与通信库。于是会出现一种最常见、也最隐蔽的失败:看起来可调度(scheduler 成功把 Pod 放上去了),但跑起来不可用(吞吐崩、尾延迟抖、NCCL 报错、训练步时不稳定)

本章聚焦于以下三个核心问题:

  • 控制面如何表达拓扑约束:让“该去哪儿跑”从拍脑袋变成可声明、可审查、可执行的约束。
  • 数据平面如何暴露资源单元:让“我到底拿到了什么”可以被工作负载和平台共同验证。
  • 如何避免“可调度但不可用”的伪成功:把拓扑从“最佳努力”升级为“可验收”。

单卡经验在多卡/多节点场景下的失效

在多卡/多节点环境下,性能瓶颈不再只由 GPU 算力决定,而是由一组链路共同决定。下文介绍这些关键链路及其影响。

性能主导因素的迁移

以下是多卡/多节点场景下影响性能的主要链路:

  • CPU ↔ GPU 的亲和性(NUMA, Non-Uniform Memory Access):GPU 挂在哪个 CPU Socket,下游内存/PCIe Root Complex 是谁,决定了数据喂给 GPU 的效率与抖动上限。
  • GPU ↔ GPU 的互联(NVLink / PCIe):同一节点内,GPU 间通信的拓扑决定了 NCCL ring/tree 的实际带宽与延迟。
  • 节点 ↔ 节点的网络(以太网 / RoCE / IB / EFA):跨节点 all-reduce、参数同步、KV cache 分片都依赖网络与 RDMA(Remote Direct Memory Access)栈质量。
  • 系统软件栈的“隐形限制”:驱动版本、NCCL/UCX、容器权限、/dev/shm、IOMMU、cgroup/CPU pinning 等,都会把“可用性”变成概率事件。

典型“伪成功”症状

以下场景中常见“调度成功但不可用”的现象:

  • 训练作业:NCCL 初始化慢/失败;步时波动大;跨节点带宽远低于预期;节点间拓扑不一致导致效率崩盘。
  • Ray 推理/Serving:同一模型副本放到了跨 NUMA 的 GPU 上,吞吐下降但 p99/p999 尾延迟暴涨;或者 worker 分散到网络质量差的节点,出现系统性抖动。
  • Ray 分布式任务:placement group 表面满足资源数,但实际落点跨机架/跨 AZ,导致“可跑但不值钱”。

结论:从单卡到多节点,本质是从“资源数量问题”升级为“资源位置问题”。

拓扑约束的三个层次

为了便于理解拓扑约束,通常将其分为三层,层级越低越贴近硬件:

  • 集群拓扑(Cluster Topology):Region / Zone / 机房 / 机架 / 交换域 / 网络平面(如是否同一 ToR、是否同一 RDMA fabric)。
  • 节点拓扑(Node Topology):NUMA 节点、CPU socket、PCIe 拓扑、GPU/NIC 挂载关系、NVLink island。
  • 设备拓扑(Device Topology):GPU 之间的 P2P 能力、NVLink 链路数量、GPU 与 NIC 的亲和(GPUDirect RDMA)、MIG(Multi-Instance GPU)实例归属等。

控制面负责将这些拓扑"表达出来并约束调度",数据平面负责将这些拓扑"暴露出来并可被验证"。

下图展示拓扑约束的三个层次。集群拓扑(蓝色区域,最上层):Region/Zone/机房/机架/交换域/网络平面,适用于跨机房部署、容灾、网络质量约束。节点拓扑(黄色区域,中间层):NUMA 节点/CPU socket/PCIe 拓扑/GPU NIC 挂载关系/NVLink island,适用于单节点多卡训练、PCIe/NVLink 优化、NUMA 亲和。设备拓扑(绿色区域,最底层):GPU 之间 P2P 能力/NVLink 链路数量/GPU 与 NIC 亲和/MIG 实例归属,适用于 MIG 虚拟化、GPU-GPU 通信优化、RDMA 亲和。底部灰色区域说明控制面与数据面的职责分工:控制面将拓扑表达并约束调度(Kubernetes 的 nodeSelector/affinity/spread/gang + Ray 的 Placement Group),数据平面将拓扑暴露并可验证(NFD、GPU/NIC 拓扑采集)。核心理念:从单卡到多节点,本质是从资源数量问题升级为资源位置与结构问题。

图 1: 拓扑约束的三个层次:从集群到设备
图 1: 拓扑约束的三个层次:从集群到设备

控制面:Kubernetes 如何表达拓扑约束

Kubernetes 默认调度以“资源计数 + 约束过滤”为主。要让其理解拓扑,需用到以下原语:

节点选择与亲和(NodeSelector / NodeAffinity)

通过标签将“节点能力/位置”编码成可声明条件:

  • topology.kubernetes.io/zone=...
  • kubernetes.io/hostname=...
  • 自定义:gpu.nvidia.com/arch=hopperrdma=truenvlink.island=...numa.policy=...

适用于粗粒度过滤(如同 AZ、同机房、必须 RDMA 等),但不适用于细粒度“同一节点内 GPU 亲和”或“跨节点成组”需求(此时需更强语义)。

反亲和与分布(PodAntiAffinity / TopologySpreadConstraints)

通过分散副本到不同故障域或网络域,避免“同机架/同节点热点”:

  • 推理副本:跨节点/跨机架 spread,提高容灾与尾延迟稳定性。
  • 训练 worker:通常更希望“靠近”而不是 spread(此时需用 gang + 机架亲和)。

组调度(Gang Scheduling)

多卡/多节点训练的核心不是“一个 Pod 能不能放”,而是“一组 Pod 能否一起放到满足拓扑的资源集合上”。

在原生 Kubernetes 中,组调度能力尚在完善。常见方案包括:

  • Volcano:PodGroup / queue / priority / preemption(偏批处理语义)。
  • Kueue:准入 + 配额 + 资源承诺/归还(偏治理语义)。

无论选用哪种方案,核心目标都是:

要么整组满足拓扑并一起启动,要么都不启动。

控制面:Ray/KubeRay 如何表达“资源位置”

Ray 的抽象是“资源与调度”,KubeRay 负责将这些抽象落到 Kubernetes 上。需理解两套语义如何叠加。

Ray 的资源表达:从“数量”到“形状”

Ray 常见的资源表达方式包括:

  • num_cpus / num_gpus:数量型资源(最基础)。
  • 自定义资源:如 {"accelerator_type:A100": 1}{"rdma": 1}(用于约束落点)。
  • Placement Group:将一组任务/actor 以“bundle”打包调度,并指定策略:
    • STRICT_PACK:尽量同节点(适合单节点多卡,最强 locality)。
    • STRICT_SPREAD:强制分散(适合高可用副本或跨节点并行但要求分散)。

实战建议:多节点训练/多 actor 并行时,优先用 placement group 明确“通信边界”,否则只能依赖调度器默认行为。

KubeRay 的落地:WorkerGroupSpec + K8s 约束

KubeRay 的 RayCluster / RayJob 通常按 head/worker 分组定义 PodTemplate。可将 Kubernetes 的拓扑约束写入每个 group:

  • 训练 worker group:nodeAffinity 约束到同一网络域(如同机架/同 IB fabric),并配合 gang(Volcano/Kueue)。
  • 推理副本 group:topology spread 到不同节点/不同故障域,降低尾延迟系统性风险。
  • 需要 RDMA 的 group:强制 rdma=true,并加 admission 校验。

Ray 的 placement group 与 Kubernetes 的 affinity/spread 并不互斥:

  • Kubernetes 负责“候选节点集合”(能跑、在哪儿跑)
  • Ray 负责“组内结构”(谁跟谁在一起、谁必须分开)

数据平面:如何暴露“你拿到的资源单元”

控制面负责“表达约束”,数据平面则必须将资源单元暴露为可观测、可校验的事实。否则平台只能凭标签与静态配置猜测拓扑,伪成功难以避免。

节点侧:发现与标注(Discovery & Labeling)

需将“拓扑事实”转化为节点标签或可查询信息。常见方式包括:

  • Node Feature Discovery(NFD, Node Feature Discovery):将硬件能力/特征打到 Node label。
  • GPU/NIC 拓扑采集:将 NVLink island、PCIe Root Complex、NIC 亲和等生成标签或 CRD(Custom Resource Definition,具体实现相关)。
  • 网络域标签:机架、ToR、fabric id(来自机房资产系统或自动发现)。

目标是让调度约束不依赖人工维护,否则维护成本极高。

设备侧:GPU 资源暴露与隔离

根据所选数据平面(整卡、MIG、共享虚拟化),暴露的资源单元不同:

  • 整卡:资源单元清晰,但仍需暴露拓扑(如 GPU0 和 NIC0 的亲和、GPU0/1 是否 NVLink)。
  • MIG(Multi-Instance GPU):资源单元离散且带强隔离,需要额外暴露“实例属于哪张物理卡/哪组 NVLink”信息,避免“实例可分配但通信不可控”。
  • 共享虚拟化(如 HAMi 类):更需可观测性与干扰检测,否则无法证明共享后性能是否满足 SLA(Service Level Agreement,服务等级协议)。

避免“可调度但不可用”:将拓扑约束升级为可验收

伪成功往往源于缺少“端到端校验”。建议将校验分为三层:准入校验、启动校验、运行时验收

准入校验(Admission)

在作业进入队列或被准入前,检查是否声明了必要的拓扑需求,且集群中存在满足条件的资源池:

  • 需要 RDMA 的训练:必须声明 rdma=true,且配额池中有对应资源。
  • 需要同节点多卡(NVLink)的推理:必须声明 nvlink=true 或“同 island”标签。
  • 多节点训练:必须声明 minNodesgpusPerNodetopologyScope(同机房/同机架/同 AZ)。

结果只有两种:可准入 / 不可准入。避免作业“先进队列再慢慢失败”。

启动校验(Startup Probing)

作业启动时,在 worker init 阶段做快速自检,尽早暴露“不可用”:

  • GPU ↔ GPU P2P/NVLink 可用性探测(同节点)
  • NCCL/UCX 初始化探测(跨节点)
  • NIC/IB 设备存在与权限(容器内可见、驱动匹配)
  • /dev/shm、hugepage、CPU pinning/NUMA policy 是否满足

启动校验失败应快速 fail-fast,并将失败原因写入事件与指标系统,避免“挂起与重试风暴”。

运行时验收(SLO/SLA)

将“拓扑是否正确”转化为可观测指标与验收门槛:

  • 训练:
    • NCCL all-reduce 带宽/延迟(可用基准测试或训练过程 proxy 指标)
    • step time 的 p95/p99 抖动
    • GPU util、PCIe/NVLink throughput、网络吞吐与重传
  • 推理(Ray Serve / vLLM on Ray):
    • p99/p999 latency 与 tail amplification
    • 每卡吞吐稳定性(标准差/变异系数)
    • 关键路径的 CPU NUMA 远端访问比例(若可采集)

当验收不达标时,排查方向主要有两类:

  1. 约束未表达清楚(调度放错地方)
  2. 资源单元未暴露清楚(以为有 NVLink/有 RDMA,实际没有或不可用)

下图展示避免"可调度但不可用"的三层校验体系。准入校验(红色区域):作业进入队列或被准入前,检查是否声明必要的拓扑需求、集群中是否存在满足条件的资源池,结果只有可准入或不可准入两种,避免先进队列再慢慢失败。启动校验(黄色区域):作业启动时 worker init 阶段做快速自检,包括 GPU↔GPU P2P/NVLink 可用性、NCCL/UCX 初始化、NIC/IB 设备与权限、/dev/shm/hugepage/CPU pinning/NUMA policy,要求快速 fail-fast 并将失败原因写入事件与指标系统。运行时验收(蓝色区域):将拓扑正确性转化为可观测指标,训练验收 NCCL all-reduce 带宽延迟、step time 的 p95/p99 抖动、GPU util 等,推理验收 p99/p999 latency、每卡吞吐稳定性、CPU NUMA 远端访问比例。底部说明验收不达标时的两个排查方向:约束未表达清楚(调度放错地方)、资源单元未暴露清楚(以为有 NVLink/RDMA 实际没有或不可用)。核心理念:伪成功源于缺少端到端校验,必须把拓扑从最佳努力升级为可验收。

图 2: 避免可调度但不可用:三层校验体系
图 2: 避免可调度但不可用:三层校验体系

参考组合:从"能跑"到"可交付"的三种模式

下表总结了三种常见的 GPU 平台成熟度路径,便于后续架构组合参考。

这是三种典型模式的对比:

模式适用场景关键点
单节点多卡优先(最强 locality)单机多卡推理、单机训练、低运维复杂度团队- K8s:强制同节点(nodeAffinity + 资源 bundle)
- Ray:placement group STRICT_PACK
- 数据平面:整卡或 MIG(强调实例与物理卡映射可见)
多节点训练(通信优先 + gang)分布式训练/微调、Ray Train、多节点数据并行- gang:Volcano 或 Kueue(保证整组准入/启动一致)
- 网络域亲和:同机房/同 fabric
- 启动校验:NCCL/UCX/RDMA 预检必做
推理多副本(稳定性优先 + spread)在线推理、多租户、多副本 HA- spread:跨节点/跨故障域分散,避免同域抖动
- 资源治理:配额/准入(Kueue)防止被训练挤爆
- 验收:以尾延迟为硬指标,优先“稳定”而非“峰值吞吐”
表 1: GPU 平台多节点能力落地模式对比

下图展示三种典型落地模式的演进路径。模式 1(绿色):单节点多卡优先(最强 locality),适用场景是单机多卡推理、单机训练、低运维复杂度团队,关键技术点包括 K8s 强制同节点(nodeAffinity + 资源 bundle)、Ray placement group STRICT_PACK、数据平面整卡或 MIG(强调实例与物理卡映射可见)。模式 2(黄色):多节点训练(通信优先 + gang),适用场景是分布式训练/微调、Ray Train、多节点数据并行,关键技术点包括 gang(Volcano 或 Kueue 保证整组准入启动一致)、网络域亲和(同机房同 fabric)、启动校验(NCCL/UCX/RDMA 预检必做)。模式 3(蓝色):推理多副本(稳定性优先 + spread),适用场景是在线推理、多租户、多副本 HA,关键技术点包括 spread(跨节点跨故障域分散避免同域抖动)、资源治理配额准入(Kueue 防止被训练挤爆)、验收以尾延迟为硬指标(优先稳定而非峰值吞吐)。底部展示成熟度演进路径:从能跑(模式 1)→ 可交付(模式 2)→ 可运营(模式 3)。核心理念:多节点 GPU 平台的核心挑战是让可调度真正等于可用,避免伪成功。

图 3: 三种典型落地模式:从能跑到可交付
图 3: 三种典型落地模式:从能跑到可交付

落地清单(Checklist)

上线 Ray/KubeRay 多节点能力前,建议至少明确以下问题:

  • 拓扑事实从哪来?(NFD/资产系统/自动探测)
  • 拓扑如何表达?(label/affinity/spread/gang + Ray placement group)
  • 资源单元是什么?(整卡/MIG/共享;是否可观测可计量)
  • 准入是否强制?(缺少拓扑声明能否进入队列/能否被准入)
  • 启动是否 fail-fast?(NCCL/RDMA/NVLink/NUMA 校验)
  • 验收指标是什么?(训练 step time 抖动、推理尾延迟、通信带宽)
  • 失败如何归因?(事件 + 指标 + 日志链路,能快速区分“放错地方”还是“资源不真”)

总结

从单卡到多节点,GPU 平台的挑战已从资源数量升级为资源位置与结构。Kubernetes 侧通过 affinity/spread/gang 将“候选落点”转化为可执行约束;Ray 侧用 placement group 明确“组内结构”语义;数据平面则需将拓扑事实与资源单元暴露为可验证信号。唯有如此,才能避免“可调度但不可用”的伪成功,让分布式能力真正成为可交付的 GPU 平台能力。

创建于 2025/12/30 更新于 2026/01/02 5816 字 阅读约 12 分钟