基于 NVIDIA Topograph 的拓扑感知工作负载调度
AI 工厂是受电力限制的系统,只有在充分优化时才能发挥最大价值。GPU 工作负载的放置是实现优化的关键。不佳的放置策略会拓扑域碎片化,迫使流量穿越共享链路,从而降低吞吐量、推高任务成本,并导致 GPU 在等待数据而非推进计算时,白白消耗已预留的电力。
GPU 在训练和推理期间持续交换数据,因此分布式工作负载受益于通信局部性。NVIDIA NVLink 和 NVLink Switch 在机架级 GPU 域内提供高带宽、全对全的纵向扩展连接,而 NVIDIA Spectrum-X Ethernet 则在各系统和机架之间提供可预测、低延迟的横向扩展网络。
调度器只有掌握这些 GPU 和 fabric 关系的实时、准确视图,才能高效地放置工作负载;然而,随着集群变化而保持该视图的实时性,正是实际部署中放置环节常失效的症结所在。
NVIDIA Topograph 解决了这一难题。它从云 API 或本地 fabric 系统中发现集群拓扑,将其归一化为通用模型,并以各工作负载管理器所需的格式发布:Kubernetes 节点标签、Slurm 拓扑配置或 Slinky ConfigMaps。在 NVIDIA DSX OS 集群编排层内,Topograph 与 动态资源分配(DRA) 和 KAI Scheduler 协同工作,以在 AI 工厂基础设施上实现拓扑感知的 gang 调度。
本文将逐步介绍如何部署 Topograph,并利用它在 Kubernetes、Slurm 和 Slinky 上调度拓扑感知的工作负载。
核心拓扑问题
Topograph 映射集群硬件的连接方式,使调度器能够优先使用邻近资源。可以将网络视为道路系统:同一局部性域内的 GPU 拥有短且高带宽的路径,而域间流量则需穿越更多共享链路和交换机。将紧密耦合的工作负载分散到相距较远的域中,可能加剧争用并增加延迟,因此 Topograph 有助于将工作负载放置在最高效的位置,从而规避这些瓶颈。
现代 NVIDIA Quantum InfiniBand 端口速率可达 800 Gb/s;而 NVIDIA NVLink 的第五代(如 NVIDIA Blackwell,即 GB200/GB300)在专用 NVLink Switch 架构下提供每 GPU 1.8 TB/s 的双向带宽,第六代(Vera Rubin)则提升至每 GPU 3.6 TB/s。这种无阻塞的全互联设计让每块 GPU 独享链路,无需在负载下共享带宽。具备实时拓扑视图的调度器可以优先选择拓扑距离更近的 GPU。
Slurm 和 Kubernetes 均支持拓扑感知分配,但调度器只能基于其观察到的拓扑进行决策。Topograph 会按需或在监控的集群发生变化时重新生成该视图,使调度器基于最新数据而非人工维护的快照运行。
跨环境的统一模型
Topograph 是一个开源工具包,用于识别集群网络拓扑,使工作负载管理器能够做出拓扑感知的调度决策。它包含两个核心概念:provider 和 engine。Provider 负责从云 API 或本地系统中发现拓扑,并将其归一化为标准模型;Engine 则将该模型转换为 Slurm 配置、Kubernetes 标签、Slinky ConfigMaps、Node Feature Discovery(NFD)资源或面向实例的拓扑 JSON。
已与 Topograph 完成集成的云服务商包括 Google Cloud、Lambda、Nebius、Nscale 和 OCI,更多云及托管服务商的集成正在开发中。
本地部署时,可配合 ibnetdiscover 使用 InfiniBand provider,或者对于 Spectrum-X 或 Multi-Node NVLink (MNNVL) 域,使用 NetQ。
provider 接口是开放的,运维人员可以为自己的环境新增 provider,并向上游贡献。
环境与引擎支持
| 环境或 provider | Kubernetes | Slurm | Graph | ||
| Node labels (k8s) | NFD resources (nfd) | Slinky ConfigMap (slinky) | |||
| 云及托管服务提供商 | |||||
| Crusoe | 是 | 是 | 是 | 是 | 是 |
| Google Cloud | 是 | 是 | 是 | 是 | 是 |
| Lambda | 是 | 是 | 是 | 是 | 是 |
| Nebius | 是 | 是 | 是 | 是 | 是 |
| Nscale | 是 | 是 | 是 | 是 | 是 |
| Oracle Cloud Infrastructure (OCI) | 是 | 是 | 是 | 是 | 是 |
| 本地部署模式 | |||||
| Kubernetes 中的 InfiniBand | 是 | 是 | 是 | 支持 | 支持 |
| 裸金属或虚拟机上的 InfiniBand | 否 | 否 | 否 | 支持 | 支持 |
| 本地部署的网络与拓扑 | |||||
| Spectrum-X 或 NetQ 管理的网络 | 支持 | 支持 | 支持 | 支持 | 支持 | MNNVL NVLink 分区(仅限 DRA 块拓扑) | 否 | 否 | 支持 | 否 | 否 |
范围与解读。此矩阵反映的是 2026 年 9 月 16 日时点的当前上游主干代码版本。它展示了支持的提供器与引擎输出组合;具体需求可能因 Topograph 版本、环境和提供器配置而异。
- Crusoe 提供器从 Crusoe Managed Kubernetes 节点读取网络和加速器域标签;因此,该提供器要求 Topograph 运行在 Kubernetes 环境中。
- Slurm 引擎可以运行在 Kubernetes 中,但要求其配置的
topology.conf输出路径所指向的卷必须可写。 - NFD 引擎需要启用 alpha 版本的 NodeFeatureGroupAPI 功能门控。Kubernetes 引擎则通过发布节点标签来实现。
保持集群视图同步更新
五个组件共同确保该视图保持最新状态:
- API Server:校验请求、去重并分发发现任务。
- Node Observer:监控已配置的 Kubernetes 节点或 Pod 变更及 API 就绪状态,随后触发带有重试机制的重新生成请求。
- Node Data Broker:收集每个节点的属性并将其存储为节点注解。
- Provider:将云端或网络数据转换为规范表示。
- Engine:以调度器可理解的格式写入该表示。
客户端如何查询拓扑
API server 提供五个服务接口:
POST /v1/generate– 提交异步请求并返回其 ID,HTTP 状态码 202。GET /v1/topology?uid=<request-id>– 处理中返回 HTTP 202,完成后返回 HTTP 200 及结果。POST /v1/lookup– 不重复提交,直接返回相同请求体的缓存状态或结果。GET /healthz– 存活端点。GET /metrics– 暴露 Prometheus 指标。
聚合延迟是必需的,通常为 15 秒。完全相同的重复请求会重置尾部计时器并只处理一次,从而减少集群事件突发时的冗余工作。
在没有生产硬件的情况下进行测试,仿真模型描述了节点和交换机层次。使用 kwok-nodes 工具和 Kind/KWOK 助手,可以将这些模型转换为虚拟 Kubernetes 节点。
在 Kubernetes 上解决(引擎:k8s)
Kubernetes 默认调度器不感知物理互连层次。Topograph 通过发布提供方报告的拓扑作为节点标签来弥补这一不足,原生亲和性和拓扑感知调度器可以消费这些标签。
前置要求:Kubernetes 1.27 或更高版本、Helm 3.10+ 或 4.x、kubectl 权限,以及受支持的 provider。如需拓扑感知的 gang 调度,可选装 KAI Scheduler 或 Kueue TAS。
使用 Helm 部署 Topograph
Topograph 以 Helm chart 形式发布:
helm repo add topograph https://dsx-ai-factory.github.io/topograph helm repo update helm install topograph topograph/topograph \ --namespace topograph \ --create-namespace \ --set engine.name=k8s \ --set provider.name=<provider>
请将 <provider> 替换为与你环境对应的值。
仓库的 charts/topograph 目录中提供了示例 Helm values 文件,命名以 values.k8s 为前缀并附有简短的场景说明,每个文件都带有内联配置注释。
安装完成后,验证部署是否成功:
helm test topograph --namespace topograph
内置的测试钩子会在集群内请求 /healthz 和 /metrics,并确认响应中包含 topograph_version 指标。
确认 Pod 正在运行:
kubectl get pods -n topograph
验证节点上的拓扑标签
Topograph 用一组可变深度的标签表示网络拓扑位置,用两级层次结构表示加速器拓扑位置:
fabric.topograph.run/tier-0 # 离节点最近的交换机 fabric.topograph.run/tier-1 # 下一层网络层级 fabric.topograph.run/tier-<N> # 更多发现的层级 accelerator.topograph.run/domain # 加速器域 accelerator.topograph.run/sub-domain # 可选的嵌套子域
网络层级 0 是离计算节点最近的叶子交换机,层级编号向外递增。Topograph 只写入实际发现的层级标签,没有固定的最大深度。运维人员可以通过 Kubernetes engine 的 fabricLabels 数组和 acceleratorLabel 参数使用自定义键名,超出该数组的层级不会被标注。sub-domain 键名是固定的。
要验证标签是否已应用,执行以下命令:
kubectl get nodes --show-labels | grep -E 'fabric\.topograph\.run|accelerator\.topograph\.run'
如果标签缺失,请检查 Topograph 日志:
kubectl logs -n topograph -l app.kubernetes.io/name=topograph
注意: Topograph 反映的是实际报告的网络拓扑,而非预期拓扑。标签会在生成过程运行时刷新,例如在监控的节点或 Pod 发生变化后。网络变更的可见性取决于提供商及其触发事件。
暴露 API
API 默认是一个 ClusterIP 服务。基于上述的发行版本和命名空间,其地址为:topograph.topograph.svc.cluster.local:49021。
本地调试方法:
kubectl -n topograph port-forward svc/topograph 49021:49021 curl http://localhost:49021/healthz
使用标准 Kubernetes 调度
拓扑标签可作为 Pod 亲和性中 topologyKey 的值用于首选调度策略:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 90
podAffinityTerm:
labelSelector:
matchLabels:
app: myapp
topologyKey: fabric.topograph.run/tier-0
- weight: 70
podAffinityTerm:
labelSelector:
matchLabels:
app: myapp
topologyKey: fabric.topograph.run/tier-1
每个匹配项都会为候选节点评分,强烈倾向于现有 app=myapp Pod 所在的 tier-0 域,同时也奖励 tier-1 的局部性。由于默认调度器是逐个放置 Pod 的,这属于偏好设置,而非全局最优的 gang 调度。
KAI Scheduler 和 Kueue 可以利用相同的节点标签实现拓扑感知的 gang 调度。Kubernetes 1.36 还通过 拓扑感知工作负载调度 引入了 alpha 阶段的KEP-5732。上游的 beta 版本工作正在进行中;建议关注增强功能跟踪器,而非依赖特定的未来版本。
使用 KAI Scheduler 进行拓扑感知的 Gang 调度
KAI Scheduler(由 NVIDIA 捐赠的 CNCF 沙箱项目)将节点标签组织为层级结构:
apiVersion: kai.scheduler/v1alpha1
kind: Topology
metadata:
name: cluster-topology
spec:
levels:
- nodeLabel: topology.kubernetes.io/zone
- nodeLabel: fabric.topograph.run/tier-1
- nodeLabel: fabric.topograph.run/tier-0
- nodeLabel: kubernetes.io/hostname
使用 kubectl apply -f cluster-topology.yaml 应用该配置,然后为多 Pod 的 Job 添加注解:
apiVersion: batch/v1
kind: Job
metadata:
name: topology-aware-workers
annotations:
kai.scheduler/topology: cluster-topology
kai.scheduler/topology-required-placement: fabric.topograph.run/tier-1
kai.scheduler/topology-preferred-placement: fabric.topograph.run/tier-0
spec:
parallelism: 4
completions: 4
template:
metadata:
labels:
app: inference-worker
spec:
schedulerName: kai-scheduler
restartPolicy: Never
containers:
- name: worker
image: nvcr.io/nvidia/nemo:latest
resources:
limits:
nvidia.com/gpu: 1
必需注解将团伙调度限制在单个 tier-1 域内。优选注解在条件允许时,会请求 KAI 将 Pod 集中在 tier-0 域内,但允许在必需边界内使用多个 tier-0 域。
更多高级拓扑感知调度示例,请参阅 Grove 和 NVIDIA Dynamo 的文档。
Grove 提供 Kubernetes API 和 Operator,用于实现层级化团伙调度、拓扑感知放置及协同扩缩容。Dynamo 是一个开源分布式推理服务框架,可与 Grove 集成以进行 Kubernetes 工作负载编排。
通过 NFD 发布拓扑信息(引擎:nfd)
Topograph 也支持已在使用 Node Feature Discovery 的用户。nfd 引擎会为每个选定的拓扑节点发布一个 NodeFeature,并为每个不同的 fabric-tier、XCLR-domain 和 XCLR-sub-domain 值发布一个 NodeFeatureGroup。NFD master 负责评估这些规格,并维护各组的 status.nodes 成员列表。
请先安装 nfd 并启用 alpha 阶段的 NodeFeatureGroupAPI feature gate(默认关闭)。然后指定引擎和 NFD master 所在的命名空间:
engine: name: nfd nfdNamespace: node-feature-discovery
当下游组件需要消费 NodeFeatureGroup 对象时可以使用这种输出,但它不能替代 Kubernetes 的 topologyKey 标签。如果要用原生 Pod 亲和性、KAI Scheduler 或 Kueue TAS,请继续使用 engine: k8s。Helm chart 会把 NFD 权限限制在 nfd 命名空间内。该引擎在 reconcile 之后会删除由 Topograph 管理的过期对象,但如果某一轮没有生成任何拓扑,则会保留上一次发布的拓扑。
在 Slurm 上解决问题(engine: slurm)
Topograph 可以生成全集群范围的 tree 和 block 格式配置,对应下图 2 的上方中央和下方中央面板。Slurm 25.05 引入了基于分区的 YAML 格式配置,Topograph 同样支持,如图所示。
安装 Topograph
Slurm 集群通常运行在 Linux 裸金属服务器或虚拟机上,此时可通过原生包管理器安装 Topograph。仓库中提供了 Debian 和 RPM 构建目标:
make deb # Debian / Ubuntu make rpm # RHEL / Rocky / SUSE包安装后不会自动启动服务,你可以先检查并编辑配置文件
/etc/topograph/topograph-config.yaml:http: port: 49021 provider: <provider> engine: slurm requestAggregationDelay: 15s将
<provider>替换为符合你环境的值。更新配置后,启动服务并验证其健康状态:
sudo systemctl enable --now topograph.service curl http://localhost:49021/healthz生成 Slurm 拓扑配置
向 Topograph 的
/v1/generate端点发送 POST 请求即可触发拓扑发现,这会重新生成 Slurm 拓扑配置。提交请求并轮询结果:
id=$(curl -s -X POST -H 'Content-Type: application/json' \ -d @payload.json http://localhost:49021/v1/generate) curl -s "http://localhost:49021/v1/topology?uid=$id"若需输出集群范围的树形拓扑,使用绝对路径:
{ "engine": { "name": "slurm", "params": { "plugin": "topology/tree", "topologyConfigPath": "/etc/slurm/topology.conf", "reconfigure": true } } }使用
topology/block配合可选的blockSizes参数可输出块形拓扑。可选参数
reconfigure用于在写入文件后执行scontrol reconfigure,默认为 false。若省略topologyConfigPath,Topograph 将直接从结果端点返回生成的内容,而非写入文件。{ "engine": { "name": "slurm", "params": { "topologies": { "gpu-block": { "partition": "gpu", "plugin": "topology/block", "blockSizes": [8, 16] }, "cpu-tree": { "partition": "cpu", "plugin": "topology/tree" }, "default": { "plugin": "topology/flat", "clusterDefault": true } }, "topologyConfigPath": "/etc/slurm/topology.yaml", "reconfigure": true } } }若希望基于节点状态自动刷新,且使用的 provider 能自动发现 Slurm 节点映射,请以 root 身份运行仓库中的脚本:
scripts/create-topology-update-script.sh -p <provider> -c /etc/slurm/topology.conf该脚本会注册一个永久的
strigger,响应节点上线和下线事件。它无法检测交换机任意重新接线或所有清单变更。在 Slinky 上求解(引擎:slinky)
由 SchedMD 开发的 Slinky 在 Kubernetes 上运行 Slurm。NVIDIA 已于 2025 年 12 月收购了 SchedMD。Topograph 的 Slinky 引擎将 Kubernetes 节点映射为
slurmdPod,并将 Slurm 拓扑数据写入 ConfigMap。Slinky 引擎支持全集群的
topology/tree和topology/block输出,以及用于分区特定配置的多拓扑 YAML。将 Topograph 作为 Helm chart 安装:
helm repo add topograph https://dsx-ai-factory.github.io/topograph helm repo update helm install topograph topograph/topograph \ --namespace topograph \ --create-namespace \ --values my-values.yaml该仓库提供了可直接适配的 Helm 示例,涵盖tree、block、按分区及InfiniBand block部署。
当选定的
slurmdPod 发生变更时,Topograph 会重新生成并更新 ConfigMap。
dra提供器是面向 MNNVL 系统的更窄范围的 Slinky 块拓扑选项。它在重新生成拓扑配置时,会读取现有的nvidia.com/gpu.clique标签。对于动态 Slurm 节点,可选的
useDynamicNodes模式还会为选定的 Kubernetes 节点添加当前 Slurm 拓扑规范的注解。ConfigMap 更新与动态节点协调是两种不同的机制,因此请选择与已部署 Slinky 配置相匹配的模式。入门指南
随着规模扩大,放置问题会累积并表现为网络拥塞。Topograph 为调度器提供由供应端报告的最新物理网络地图,使拓扑感知决策在云和本地环境中保持一致,且无需人工维护。
通过 KAI Scheduler、Kueue 及原生 Kubernetes,该地图提升了 AI 工厂的效率、每瓦令牌数及成本效益。
你可以从 dsx-ai-factory/topograph GitHub 仓库部署 Topograph,或进一步了解 DSX OS 生态系统。