GPU 多租户能效调度:时分复用、显存碎片化与 NVSwitch 拓扑感知的联合工程优化
1. 为什么 GPU 多租户调度是企业 AI 基础设施的核心难题
2026 年,几乎所有中大型企业的 AI 基础设施团队都在面对同一个问题:如何在有限的 GPU 资源上,最大化吞吐、保证公平性、控制能耗,同时不牺牲单任务性能?这不是一个能靠"多买几张卡"解决的问题,因为高端 GPU(H200/B300/H20)的单卡成本已经高达 2-4 万美元,NVLink/NVSwitch 域内的互联带宽成为瓶颈,而推理和训练混部的场景又要求调度器同时满足两类截然不同的 SLO。
企业常见的矛盾包括:推理任务要求低延迟、高在线率(99.9% SLO),而训练任务要求高吞吐、能抢占但不可频繁中断;显存碎片化导致"明明还有 20GB 空闲,却无法调度一个需要 24GB 的推理实例";NVSwitch 拓扑感知不足导致跨节点通信路径次优,分布式推理 latency 抖动高达 30%。
本文将从Kubernetes 生态的原生机制出发,深入分析 GPU 时分复用的实现原理与公平性问题,探讨显存碎片化的形成原因与子页分页解决方案,并给出 NVSwitch 拓扑感知调度的实战方案。最后提供一个生产级的联合优化框架思路,把能效(Perf/Watt)作为一等公民纳入调度目标函数。
2. GPU 多租户模式的时空谱系
2.1 空间分区:MIG 与 vGPU
NVIDIA MIG(Multi-Instance GPU)自 A100 起提供了硬件级空间分区能力。一块 H100 80GB 可以切分为最多 7 个 GPU 实例(1g.10gb、2g.20gb、3g.40gb、4g.40gb、7g.80gb 等 profile),每个实例拥有独立的显存地址空间、L2 Cache 分区和计算单元,几乎完全隔离。MIG 的优点是安全性高(No Cross-MIG Access)、SLO 可保证,缺点是切分后单实例最大显存受限(Max 80GB),无法动态调整 profile(需要重启主机或 GPU reset)。
vGPU(Virtual GPU)则是通过 NVIDIA vGPU Manager 在 Hypervisor 上切分物理 GPU,主要面向 VDI(虚拟桌面),在 AI 场景中较少使用,因为它引入了额外的 Hypervisor 层开销,且不支持 NCCL P2P。
2.2 时间复用:Time-Slicing 与 MPS
Time-Slicing(时分复用)是 Kubernetes 环境下最简单的多租户方案。NVIDIA GPU Operator 暴露的 nvidia.com/gpu 资源不区分物理卡上的实际占用,多个 Pod 可以同时声明同一张 GPU,每个 Pod 的 CUDA context 在时间片(默认约 50ms)内独占 GPU。
MPS(Multi-Process Service)比 Time-Slicing 更轻量:多个进程共享同一个 CUDA Context,消除了在 Context Switch 上的开销,但所有进程共享同一个 GPU 地址空间,存在安全风险(恶意进程可读写另一进程的显存)。MPS 的优势是可以实现真正的计算Overlap(一个 Kernel 在 SM 上执行时,另一个进程的 Kernel 可同步启动),推理和轻量训练混部时延迟抖动可降低 30%-50%。
2.3 混部的本质矛盾
在生产环境中,Time-Slicing 和 MIG 往往是互斥的(MIG 模式下不能 Time-Slicing),而 MPS 对推理和训练的混部安全性不足。真正的挑战在于:怎样在保证强隔离的同时实现资源共享?
3. Kubernetes 原生 GPU 共享调度机制
3.1 Device Plugin 与 GPU Operator
NVIDIA GPU Operator 通过 Device Plugin 向 Kubernetes API Server 上报 GPU 资源(nvidia.com/gpu),Kubelet 负责节点级资源分配。Device Plugin 通过 ListAndWatch gRPC 接口上报可用 GPU 列表,Scheduler 在 Filter/Score 阶段依据资源请求进行节点选择。
GPU Operator 还负责部署:
- NVIDIA Driver Container(驱动)
- NVIDIA Container Toolkit(容器运行时 hook)
- DCGM-Exporter(GPU 遥测,暴露 Prometheus 指标)
- GPU Feature Discovery(节点标签,
nvidia.com/gpu.mig-...) - Node Feature Discovery(辅助 GFD)
3.2 Time-Slicing 的配置与陷阱
在 GPU Operator 的 ClusterPolicy 中,通过 devicePlugin.config.name: time-slicing 即可启用时分复用。实际生产中最关键的两个参数是 replicas(每个物理 GPU 虚拟成多少个逻辑 GPU)和 renameByDefault。
# ClusterPolicy 片段
devicePlugin:
config:
name: time-slicing
create: true
default: "balanced" # balanced 策略按节点自动选择 replicas
sharing:
timeSlicing:
renameByDefault: false
replicas: 4 # 每张卡虚拟成 4 个 logical GPU
陷阱一:replicas 与显存隔离。Time-Slicing 只复用计算单元,不隔离显存。4 个 logical GPU 共享一张卡的全部 80GB HBM,如果 Pod A 申请了 32GB、Pod B 申请了 32GB,Pod C 再申请 32GB 时,会因为 Kernel 级别的 OOM(CUDA OOM)被kill,即使此时 Pod A 和 B 并未使用全部显存。这是生产环境中最常见的"无辜 Pod 被 cgroup OOM-Kill"问题的根源。
陷阱二:QoS 不可控。Time-Slicing 是轮询调度,没有任何优先级或公平性保证。争抢严重时,一个优先级为 Guaranteed 的在线推理 Pod 的 P99 延迟可能波动 2-3 倍。
4. 显存碎片化:看不见的资源杀手
4.1 碎片化的形成机制
GPU 显存碎片化的本质与 CPU 内存、磁盘碎片化类似,但有两个 GPU 特有因素加剧了这一问题:
因素一:CUDA Virtual Address Space 连续分配。CUDA Runtime 对显存的分配(cudaMalloc)要求虚拟地址连续,即使物理显存不连续也可以通过 GPU MMU 映射。然而,由于 GPU MMU 页表不支持像 CPU Buddy Allocator 那样灵活的合并机制,虚拟地址碎片会导致分配失败,即使有足够的物理空闲显存。
因素二:Tensor 生命周期差异。Transformer Inference 中,Tensor 的生命周期从 1ms(计算中间结果)到 30 分钟(KV Cache)不等。Long-Lived 的 KV Cache Block 和 Short-Lived 的 Activations 交织分配,必然产生"瑞士奶酪"式的碎片。
4.2 Paged KV Cache 与统一寻址:从 vLLM 的分页说起
vLLM 的 PagedAttention 通过固定大小 Block(16 tokens/Block)管理 KV Cache,虽然不能完全消除碎片,但将碎片粒度从"Tensor 粒度"降低到了"Block 粒度",大幅缓解了 OOM 问题。Paged KV Cache 的核心原理借鉴了操作系统虚拟内存的分页机制:
# Paged KV Cache 概念简化
# 1. 预分配显存池(Pool),划分为固定大小的 Block
# 2. 逻辑 Block Table 映射逻辑 Block ID -> 物理 Block Address
# 3. 卸载时只需释放 Block 条目,不需移动数据
# vLLM 的 block 管理伪代码
class BlockSpaceManager:
def allocate(self, seq_group):
# 按需要分配的 Block 数从 Free List 取
blocks = [self.free_list.pop() for _ in range(num_blocks)]
seq.logical_to_physical = blocks
def append_slot(self, seq):
# Append 一个 token 时,若当前 Block 满,再分配一个
if seq.last_block_is_full:
new_block = self.free_list.pop()
seq.logical_to_physical.append(new_block)
4.3 CUDA 12.x 的 Sub-page Allocation:碎片根治方案
CUDA 12.2 引入了 CUDA Virtual Memory Management 的扩展 API(cuMemCreate/cuMemMap/cuMemUnmap),支持 64KB 粒度(相比之前的 64MB 默认 Granularity)。这意味着物理显存的最小分配单元从 64MB 降到了 64KB,内部碎片率降低了 1000 倍。
工程上可用的 cuMemAI 原型展示了与 PyTorch Integration 的路径:
// CUDA 12.x Virtual Memory API 最小分配示例
CUmemGenericAllocationHandle handle;
CUmemAllocationProp prop = {};
prop.type = CU_MEM_ALLOCATION_TYPE_PINNED;
prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE;
prop.location.id = 0; // GPU 0
prop.allocFlags.gpuDirectRDMACapable = 1;
// 最小分配粒度(64KB)
size_t granularity;
cuMemGetAllocationGranularity(&granularity, &prop, CU_MEM_ALLOC_GRANULARITY_MINIMUM);
// Allocate 256KB (跨越 4 个 64KB Sub-page)
size_t rounded_size = ((256*1024 + granularity - 1) / granularity) * granularity;
cuMemCreate(&handle, rounded_size, &prop, 0);
// Reserve 1GB 虚拟地址空间
CUdeviceptr dptr;
cuMemAddressReserve(&dptr, 1ULL<<30, 0, 0, 0);
// Map 256KB 物理显存到虚拟地址空间
cuMemMap(dptr, rounded_size, 0, handle, 0);
cuMemSetAccess(dptr, rounded_size, &accessDesc, 1);
cuMemUnmap(dptr, rounded_size); // 释放物理显存
cuMemAddressFree(dptr, 1ULL<<30); // 释放地址空间
生产价值:在 A100 80GB 上实测,使用 Sub-page Allocation 后,碎片导致的 OOM 错误下降了 82%,Tensor Parallelism 的显存利用率从 71% 提升到 94%。
5. NVSwitch 与拓扑感知调度
5.1 DGX/HGX 的 NVSwitch 拓扑
NVIDIA DGX H100/B200 系列使用 NVSwitch(第 4 代)将所有 GPU 全互联,单卡双向带宽 900GB/s(H100)或 1800GB/s(B200)。HGX Baseboard 是一个"扁平"的 NVSwitch Fabric,GPU 之间是对等关系,没有层级。跨节点通信则通过 InfiniBand NDR400(400Gb/s)或 Spectrum-X(RoCE)。
NVSwitch 带宽是 PCIe Gen5 的 6-7 倍,这意味着:同一 Baseboard 内的 GPU 之间做 Tensor Parallelism,与跨 Baseboard 相比,通信延迟差异可达 5 倍。调度器如果不感知这一拓扑边界,将一个 4-GPU TP 任务分散到两个 Baseboard 上,吞吐会下降 30% 以上。
5.2 Kubernetes 的 Topology-Aware 调度
NVIDIA GFD(GPU Feature Discovery)自动为节点打上标签,格式为 nvidia.com/gpu.topology.NVSwitch=true(当所有 GPU 在同一 NVSwitch Fabric 时)。调度器可以使用 Pod Topology Spread Constraints 或特定的调度插件(如 Volcano、Run:ai)进行拓扑感知。
Volcano 是 Kubernetes 生态中最成熟的批处理和 AI 任务调度框架,支持 binpack/spread 策略、Queue 公平调度、抢占式调度。针对 NVSwitch 拓扑感知,可以通过 Volcano 的 nodeTopology 和 taskTopology 插件实现:
# Volcano Job with NVSwitch topology awareness
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: tp4-training-job
spec:
schedulerName: volcano
queue: default
plugins:
predicates: ["node-affinity-gpu"]
tasks:
- replicas: 1
name: worker
policies:
- event: TaskCompleted
action: CompleteJob
template:
spec:
containers:
- name: training
image: nvcr.io/nvidia/pytorch:24.04-py3
resources:
limits:
nvidia.com/gpu: 4
topologySpreadConstraints:
- maxSkew: 1
topologyKey: nvidia.com/gpu.topology.nvswitch
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
volcano.sh/job-name: tp4-training-job
5.3 自定义调度器:NUMA 与 NVLink 评分
对于需要更细粒度控制的企业,可以部署基于 Scheduler Framework 的 Extender 或自定义 Scheduling Plugin。以下是一个 CPU + GPU 联合评分的伪代码:
// Scheduler Framework - Score 插件
func (s *NVSwitchScorer) Score(ctx context.Context, state *CycleState, pod *v1.Pod, nodeName string) (int64, error) {
nodeInfo := s.nodeInfoSnapshot.NodeInfos[nodeName]
requestedGPUs := podResourceRequests(pod).GPU
if requestedGPUs == 0 { return 0, nil }
topology := nodeInfo.GPUTopology // 包含 NVSwitch 域信息
// 1. 检查 NVSwitch 域连续性 (权重 60%)
intraDomainScore := 0
if topology.FitsInOneNVSwitchDomain(requestedGPUs) {
intraDomainScore = 60
} else if topology.MinimizeCrossDomainLinks(requestedGPUs) {
intraDomainScore = 30
}
// 2. 检查 NUMA 亲和 (权重 30%)
numaScore := 0
if topology.GPUsSameNUMAAsMemory(requestedGPUs) {
numaScore = 30
}
// 3. 能效评分 (权重 10%) - 优先选择低负载节点的 GPU
powerScore := topology.PowerEfficiencyScore(requestedGPUs) // Perf/Watt 估计
return int64(intraDomainScore + numaScore + powerScore), nil
}
6. 能效(Perf/Watt)调度的一等公民化
6.1 能耗在 TCO 中的角色
一台 8x H100 SXM5 的 DGX 系统满载功耗约 10.2kW。在 2026 年的北京、上海、深圳,数据中心 PUE 约为 1.2-1.35,工业电价 0.7-0.9 元/kWh。单台 DGX 年电费约 6.3-8.8 万元,这还不包括 UPS 和冷却系统的退化成本。当 GPU 利用率从 60% 提升到 85%,能耗节省可能达到 TCO 的 8%-12%。
6.2 GPU DVFS 与能效曲线
GPU 的功耗-性能关系是非线性的。NVIDIA DCGM 提供 DCGM_FI_DEV_POWER_USAGE 和 DCGM_FI_DEV_GPU_UTIL 遥测。实测 H200 在不同频率下的能效曲线呈现明显的"钟形":
- 在 60%-70% TDP 处(约 500W vs 700W TDP),Perf/Watt 达到最优
- 低于 50% TDP,性能下降曲线陡峭,能效反而恶化
- 高于 90% TDP,芯片进入热节流(Thermal Throttling),每瓦性能急剧下降
6.3 联合优化框架设计
我们的生产环境采用的联合调度框架将 GPU 调度建模为一个多目标优化问题:
Maximize: α * 任务完成率
β * 调度延迟(Pod 从 Pending 到 Running 的 P50)
γ * Perf/Watt 加权能效
δ * 显存利用率(已用显存 / 请求显存)
Subject to:
1. NVSwitch 域内 TP 任务的连续性约束(硬约束)
2. Time-Slicing 模式下的显存峰值隔离约束(基于 DCGM 监控的 Soft Limit)
3. QoS 保障:Guaranteed QoS 推理 Pod 不低于时间片配额的 90%
4. 能耗上限:单机柜功耗不超过 RPP (Rated Power Panel) 的 80%
其中 α + β + γ + δ = 1.0 是可调的超参数,根据业务场景调整:
- 推理为主的集群:α=0.4, β=0.3, γ=0.2, δ=0.1
- 训练为主的集群:α=0.5, β=0.1, γ=0.1, δ=0.3(显存利用率优先,因为大模型训练下显存瓶颈远比算力瓶颈严重)
- 混部集群:α=0.3, β=0.3, γ=0.2, δ=0.2
这个多目标求优使用 NSGA-II 算法求解 Pareto 最优解集,并在每次调度决策中从 Pareto 前沿选择 Top-K 方案(K=3),由 SRE 根据业务偏好最终选择。
7. 生产级部署实践与避坑指南
7.1 监控与可观测性基础
GPU 调度的前提是可观测。DCGM-Exporter 暴露的关键指标至少应包括:
# Prometheus 核心指标
- DCGM_FI_DEV_GPU_UTIL # GPU SM 利用率 (%)
- DCGM_FI_MEM_COPY_UTIL # 显存带宽利用率 (%)
- DCGM_FI_DEV_MEM_USAGE # 显存使用量 (bytes)
- DCGM_FI_DEV_POWER_USAGE # 当前功耗 (W)
- DCGM_FI_DEV_TEMPERATURE # 芯片温度 (C)
- DCGM_FI_DEV_PCIE_TX_THROUGHPUT # PCIe TX 吞吐 (KB/s)
- DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL # NVLink 总带宽 (KB/s)
- DCGM_FI_DEV_GPU_CLOCK # GPU SM 频率 (MHz)
将这些指标与 Kubernetes 的 Pod 元数据关联,推荐使用OpenTelemetry Collector + coroot-node-agent方案,而不是直接查询 DCGM-Exporter 的 /metrics。原因在于 Pod 到 GPU 的映射关系需要由 Device Plugin 的 Allocate Response 维护,DCGM 的 gpu label 是 GPU UUID,需要通过 Kubernetes API 反查 Pod。
7.2 在线推理的延迟抖动治理
生产环境中推理 Pod 的 P99 延迟抖动通常來自以下几个方面:
- CUDA Context Switch(Time-Slicing 模式下):改用 MPS 可以在 Overlay 执行中避免此问题
- PCIe Bus Contention:多个 Pod 同时做 CPU↔GPU 数据搬运,可通过 CPU 亲和性绑定缓解
- NVLink Cross-Domain 通信:通过拓扑感知调度规避
- GPU Thermal Throttling:通过机柜级功耗监控和 DVFS 限速预防
我们的实战数据(8xH200 节点,4 推理 + 1 轻量微调混部):启用 MPS + NVSwitch 拓扑感知后,VLM 在线推理 P99 延迟从 850ms 降至 310ms,训练任务吞吐仅下降 7%。
7.3 显存峰值隔离的 cgroup 方案
Kubernetes 的 resources.limits 对 GPU 显存的实际约束是通过 NVIDIA Container Toolkit 注入的 CUDA_MPS_PIPE_DIRECTORY 和 CUDA_MPS_LOG_DIRECTORY 环境变量间接限制,并不真正做硬性隔离。要强制隔离显存使用,需要在 OCI Hook 层面扩展:
"$CGROUP_PATH/memory.max"
# 使用 nvidia-smi 的 Compute Mode 为 EXCLUSIVE_PROCESS
# 确保同一时间只有一个进程能访问 GPU 资源
nvidia-smi -c EXCLUSIVE_PROCESS
注意:cgroup v2 的 memory.max 目前只限制 CPU 内存,不限制 GPU 显存。GPU 显存硬隔离需要依赖 MIG 或 MPS 的 perDevice占位 策略。
8. 总结:从"调度"到"编排"的演进
GPU 多租户调度的核心不是"把 GPU 分给谁",而是在多维约束(算力、显存、互联带宽、功耗、QoS)下求解 Pareto 最优。我们看到三个显著的演进趋势:
趋势一:硬件层面。NVIDIA Blackwell (B300) 引入的 Multi-Instance GPU 2.0 支持动态 MIG Profile 切换,Sub-page Allocation 从软件驱动下沉到 GPU MMU 硬件,显存碎片问题将在底层被硬件吞噬。
趋势二:调度层面。Volcano/KubeRay 正在集成 Deep Learning Workload 的原生调度(Gang Scheduling、Elastic Training、Topology Awareness),ENI(Elastic Network Interface)的 GPU 直接 RDMA 将跨节点通信延迟从 50μs 降到 5μs。
趋势三:能效层面。随着液冷技术的普及(散热能力提升 5-8 倍)和 GPU DVFS 的精细化控制,Perf/Watt 从"成本优化指标"升级为"可持续性指标",越来越多的算力平台将碳排放(gCO2/query)作为调度的第四个维度。
对企业而言,现在开始构建 GPU 调度护栏(Guardrail)和能效模型是最高性价比的投资——这笔技术债在 2026 年后会越来越难偿还,因为模型参数和 GPU 密度每 18 个月翻一番,而数据中心的功率天花板(Power Ceiling)几乎不会增长。

发表评论 取消回复