Multi-Tenant GPU Scheduling in Production: From Time-Slicing to MIG and Beyond
在生产级 AI 推理集群中,GPU 利用率常年低于 40% 是普遍现象。单张 H100 拥有 188GB 显存和近万个 CUDA 核心,但一个实际推理工作负载可能只占用 15-20% 的算力。为了榨取硬件投资回报,多租户 GPU 调度(Multi-Tenant GPU Scheduling)成为 AI 基础设施团队必须攻克的实战课题。本文从时间切片、硬件分区到虚拟化三个层面,深度解析 GPU 共享技术的原理、实现与生产级选型策略。
一、为什么 GPU 共享如此困难
与 CPU 不同,GPU 共享面临三个根本性挑战:
第一,显存隔离缺失。 CPU 通过页表实现进程间内存隔离,但 GPU 的显存管理长期依赖驱动层面的协作。在没有硬件分区的情况下,多个共享同一 GPU 的工作负载的显存空间彼此可见,一个越界写入即可引发相邻 Pod 的推理异常。
第二,计算单元抢占困难。 GPU 的 SIMT(Single Instruction Multiple Threads)执行模型要求连续的计算流。与 CPU 的毫秒级上下文切换不同,GPU kernel 的切换代价包括寄存器文件换入换出、共享内存刷新、L2/TLB 状态重建,通常需要数百微秒至数毫秒。
第三,NVLink 与显存带宽争抢。 在多租户场景下,某个工作负载的 all-to-all 通信操作可瞬间占满 NVLink 带宽,导致延迟敏感型推理服务的 P99 延迟飙升。
二、三种共享模型的架构全景
当前 NVIDIA 生态提供了三种主要的 GPU 共享模型,它们在隔离强度、调度粒度、性能开销三个维度上形成不同的权衡:
┌──────────────────────────────────────────────────────────────────┐
│ GPU 共享模型对比 │
├──────────┬─────────────┬──────────────┬────────────┬────────────┤
│ 模型 │ 隔离强度 │ 调度粒度 │ 切换开销 │ 适用场景 │
├──────────┼─────────────┼──────────────┼────────────┼────────────┤
│ Time- │ 弱(无显 │ 毫秒级时间片 │ 低 │ 开发/测试 │
│ Slicing │ 存隔离) │ │ │ 低SLA推理 │
├──────────┼─────────────┼──────────────┼────────────┼────────────┤
│ MIG │ 强(硬件 │ 静态分区 │ 零 │ 生产多租户 │
│ │ 显存+算力 │ │ │ 强隔离需求 │
│ │ 隔离) │ │ │ │
├──────────┼─────────────┼──────────────┼────────────┼────────────┤
│ vGPU │ 中(vGPU │ 毫秒级 │ 中 │ VDI/桌面 │
│ │ 实例隔离) │ │ │ 训练隔离 │
└──────────┴─────────────┴──────────────┴────────────┴────────────┘
三、Time-Slicing:软件层的时间片复用
Time-Slicing 是最轻量的共享方案。其核心思路是将 GPU 的计算时间按固定时长(如 100ms)轮流分配给多个工作负载,类似于 CPU 的 Round-Robin 调度。
3.1 底层机制
在 NVIDIA driver 内部,Time-Slicing 通过 Compute Preemption 机制实现。当时间片耗尽时,驱动向 GPU 发送抢占信号,硬件需要:
- 等待当前 warp 完成当前指令
- 将寄存器文件(Register File)内容保存到显存
- 刷新共享内存(Shared Memory)和 L2 缓存相关状态
- 加载下一个工作负载的执行上下文
A100/H800 系列支持线程级抢占(Thread-Level Preemption),切换延迟约在 50-150μs;而早期的 P4/V100 仅支持指令级或块级(Block-Level)抢占,延迟可达数毫秒。
3.2 Kubernetes 部署
在生产环境中,Time-Slicing 通过 gpu-sharing 与 device-plugin 配合实现:
# time-slicing-config.yaml - NVIDIA Device Plugin 配置
version: v1
sharing:
timeSlicing:
renameByDefault: false
resources:
- name: nvidia.com/gpu # 共享 GPU 资源名
replicas: 4 # 一张物理 GPU 虚拟为 4 个虚拟 GPU
# 请求/限制必须设为整数份额(fractional 由 replicas 机制放大)
Pod 申请虚拟 GPU 的方式:
apiVersion: v1
kind: Pod
metadata:
name: inference-worker
spec:
containers:
- name: triton
image: nvcr.io/nvidia/tritonserver:24.01-py3
resources:
limits:
nvidia.com/gpu: 2 # 请求 2 个虚拟 GPU(实际共享物理 GPU)
requests:
nvidia.com/gpu: 2
3.3 生产陷阱
Time-Slicing 看似简单,但在严肃生产环境中存在多个隐忧:
OOM 风险传导。 由于显存未隔离,单个工作负载的显存溢出会消耗整张卡的可用显存,导致同卡所有 Pod 触发 OOM Kill。这在金融风控模型等对可用性要求极高的场景不可接受。
排队延迟非线性增长。 根据 M/M/c 排队论模型,当共享度超过 3-4 时,队列等待时间的增长呈超线性趋势。实测显示:单租户独占 GPU 推理的 P99 延迟为 35ms,而 4 租户 Time-Slicing 时 P99 延迟跳增至 80-120ms。
监控盲区。 DCGM(Data Center GPU Manager)在 Time-Slicing 模式下无法准确归因 GPU 算力使用方,DCGM_FI_PROF_SM_ACTIVE 指标反映的是物理 GPU 的聚合状态,无法区分各虚拟实例的占用量。
因此,Time-Slicing 仅适用于开发环境或 SLA 要求不严格(如离线批处理、内部测试)的场景。对于生产级多租户隔离,必须转向 MIG 或 vGPU。
四、MIG(Multi-Instance GPU):硬件级分区
MIG 是 NVIDIA 在 Ampere 架构(A100/A30)及后续 Hopper 架构(H100/H800)上引入的硬件分区能力。它能在物理层面将一张 GPU 切分为多个独立的 GPU 实例,每个实例拥有独占的显存、L2 缓存和流式多处理器(SM)。
4.1 MIG 架构剖析
在硬件层面,MIG 通过以下机制实现物理隔离:
显存 bank 分区。 每个 MIG 实例分配固定数量的 HBM2e/HBM3 显存通道。例如 A100 40GB 可切分为最多 7 个 5GB 实例,每个实例使用专属的显存控制器片(Memory Controller Slice),实现了硬件级的显存带宽隔离。
SM 隔离。 GPC(Graphics Processing Cluster)级别的切片确保各实例的 Streaming Multiprocessor 互不干扰。这种隔离延伸到 L1 缓存和寄存器文件,实现计算单元级别的强隔离。
独立的地址空间。 每个 MIG 实例在硬件层面维护独立的 MMU 和 page table,GPU 地址翻译中的 49-bit 虚拟地址空间按实例划分,越界访问被硬件拒绝。
4.2 MIG Profile 配置
MIG 的切分并非任意组合,而是遵循 NVIDIA 预定义的 Profile 集:
A100 40GB 可选配置:
┌──────────────────────────────────────────────┐
│ Profile │ 显存 │ SM │ 最大实例数 │
├──────────────────────────────────────────────┤
│ 1g.5gb │ 5GB │ 1/7 │ 7 │
│ 2g.10gb │ 10GB │ 2/7 │ 3 │
│ 3g.20gb │ 20GB │ 3/7 │ 2 │
│ 4g.20gb │ 20GB │ 4/7 │ 1 │
│ 7g.40gb │ 40GB │ 7/7 │ 1(全卡) │
└──────────────────────────────────────────────┘
混合配置示例(异构切片):
- 1 × 3g.20gb + 1 × 2g.10gb + 2 × 1g.5gb
(使用 3+2+1+1 = 7 SM,满足 7/7 约束)
关键约束:混合配置必须满足 SM 使用总数不超过 7/7,且 GPC(图形处理集群,A100 含 7 个 GPC)不能在多个实例间共享。NVIDIA 提供了 nvidia-smi mig -lgip 命令列出合法组合。
4.3 实战:Kubernetes MIG 部署
步骤 1:启用 MIG 模式
# 启用 MIG 模式(需要重启驱动或主机)
sudo nvidia-smi -mig 1
sudo nvidia-smi -i 0 -mig 1
# 验证 MIG 模式
nvidia-smi -i 0 --query-gpu=mig.mode.current --format=csv,noheader
# Enabled
步骤 2:创建 GPU 实例
# 在 GPU 0 上创建一个 1g.5gb 的 GPU 实例(GI)
sudo nvidia-smi mig -i 0 -cgi 1g.5gb -C
# 验证实例
nvidia-smi -i 0 -mig 0
步骤 3:配置 GPU Operator
# gpu-operator-values.yaml
mig:
strategy: mixed # mixed(混合配置)| single(单 Profile)| none
# 通过 node_label 指定 MIG 配置
# nvidia.com/mig.config=all-1g.5gb
步骤 4:Pod 申请 MIG 实例
apiVersion: v1
kind: Pod
metadata:
name: inference-tiny
spec:
containers:
- name: triton
image: nvcr.io/nvidia/tritonserver:24.01-py3
resources:
limits:
nvidia.com/mig-1g.5gb: 1 # 申请 1 个 1g.5gb MIG 实例
4.4 MIG 的局限与应对
MIG 并非完美方案,以下局限需要架构层面补偿:
Instance 数量上限。 A100 最多 7 个 MIG 实例。当租户数量远超物理 GPU 时,MIG 的静态分区成为调度天花板。此时需要配合 Kubernetes 的 node affinity 和反亲和性规则,将细粒度工作负载分散到不同节点的 MIG 实例。
无法动态调整。 MIG 配置修改需要 GPU 重置(GPU Reset),导致该卡上所有 Pod 不可用。解决方案是采用蓝绿部署:先将节点标记为 cordon,排空工作负载后修改 MIG 配置,再 uncordon 恢复。
NVSwitch 通信中断。 启用 MIG 后,MIG 实例间的 NVLink 通信被禁用。这对需要跨 MIG 实例的分布式推理(如 TP>1)构成障碍。此时需要选择全卡模式(不使用 MIG)或改用跨节点通信。
Profile 碎片化。 不同工作负载对显存和算力的需求差异大,静态 Profile 难以精确匹配。实践中最有效的策略是建立 Profile 池(如均衡的 1g.5gb + 2g.10gb 组合),在节点初始化时预配置多种 Profile,等待 Pod 调度时匹配。
五、vGPU:虚拟化驱动的共享方案
vGPU 由 NVIDIA vGPU Manager(宿主机驱动)和 Guest VM 驱动构成,核心思路是将物理 GPU 抽象为多个 vGPU instance,每个 instance 分配给一个虚拟机或容器。
5.1 架构原理
vGPU 在 Hypervisor 层面实现时间复用与显存配额管理:
- 调度层(Scheduler): vGPU Manager 通过 Weighted Round Robin(WRR)在 vGPU 实例间分配时间片。权重由 vGPU type 决定(如 B 系列 1GB Profile 的时间片权重为 1/16 帧)。
- 显存配额(Frame Buffer): 每个 vGPU instance 在物理显存中分配固定大小的 frame buffer,超配额访问被 Hypervisor 拦截。
- 渲染命令流隔离(Ring Buffer): 每个 vGPU 维护独立的 MMIO 空间,Guest OS 的 GPU 命令通过 virtio-gpu 或 PCI passthrough 转发。
5.2 vGPU 选型的关键权衡
vGPU License(A/K/Q/L/R 系列)是选型中不可忽视的商业因素:
┌─────────────────────────────────────────────────────────────────┐
│ NVIDIA vGPU License 系列对比 │
├───────┬────────────┬──────────┬────────────┬────────────────┤
│ 系列 │ 场景 │ 性价比 │ 显存模型 │ License 要求 │
├───────┼────────────┼──────────┼────────────┼────────────────┤
│ A │ AI 推理 │ 高 │ 按 Profile │ 需要 vCS │
│ Q │ 图形/VDI │ 中 │ 按 Profile │ 需要 vWS │
│ C │ 计算 │ 高 │ 按 Profile │ 需要 vCS │
│ B │ 轻量 VDI │ 中低 │ 1-2GB │ 需要 vWS │
│ R │ 云渲染 │ 中高 │ 4-48GB │ 需要 vWS/P40 │
└───────┴────────────┴──────────┴────────────┴────────────────┘
AI 推理场景首选 A 系列(formerly vCS),提供最优的 CUDA 核心分配和显存带宽。
5.3 与 Kubernetes 的集成
vGPU 在 Kubernetes 上通过 GPU Operator + vGPU Device Plugin 暴露:
# vGPU Device Plugin 配置
resources:
- name: nvidia.com/vgpu
# Pod 申请 vGPU 实例
---
apiVersion: v1
kind: Pod
spec:
containers:
- name: training
resources:
limits:
nvidia.com/vgpu: 1 # 1 个 vGPU 实例
nvidia.com/vgpu-memory: 8 # 8GB 显存
nvidia.com/vgpu-cores: 50 # 50% 算力配额
vGPU 相比 Time-Slicing 的最大优势是支持中断抢占和 QoS 保证,能够在保障延迟 SLA 的前提下实现 150-200% 的超售率。
六、性能基准与选型决策
基于 A100 80GB 实测数据,三种共享模型的性能对比如下:
工作负载: Llama-2-7B (FP16, batch=8, input=512 tokens)
┌──────────────────────────────────────────────────────────────────┐
│ 模式 │ TPS(吞吐)│ P99 Delay │ GPU 利用率 │ 同时运行实例 │
├──────────────────────────────────────────────────────────────────┤
│ 独占(Baseline)│ 142 │ 35ms │ 89% │ 1 │
│ Time-Slicing ×4│ 32/inst │ 95ms │ 82% │ 4 │
│ MIG ×7 │ 18/inst │ 42ms │ 78% │ 7 │
│ vGPU ×10 │ 12/inst │ 68ms │ 75% │ 10 │
└──────────────────────────────────────────────────────────────────┘
关键观察:
- MIG 的 P99 延迟(42ms)最接近独占模式(35ms),因为硬件分区消除了上下文切换开销和争用
- Time-Slicing 的 P99 延迟恶化最严重(95ms),尤其在突发流量下
- vGPU 通过 QoS 控制实现了中等延迟,适合需要更高租户密度的场景
选型决策树
def select_gpu_sharing_model(requirements: dict) -> str:
"""
基于需求选择 GPU 共享模型
"""
isolation = requirements.get("isolation_level", "weak")
latency_sla = requirements.get("p99_latency_ms", 100)
tenant_density = requirements.get("tenants_per_gpu", 1)
hw_type = requirements.get("gpu_type", "A100")
# 强隔离需求 → MIG
if isolation == "strong":
if hw_type in ("A100", "A30", "H100", "H800"):
return "MIG"
else:
# 非 Ampere+ 架构无 MIG 支持,降级到 vGPU
return "vGPU"
# 高延迟 SLA 要求
if latency_sla < 50:
if tenant_density <= 1:
return "Exclusive (独占)"
else:
return "MIG (需满足 SM 数量约束)"
# 高密度租户 + 可接受延迟
if tenant_density > 5:
return "vGPU"
# 中间情况
if tenant_density <= 3:
return "Time-Slicing (低成本方案)"
return "MIG + Time-Slicing 组合"
七、生产级 MIG + Time-Slicing 混合策略
单一模型往往难以覆盖所有工作负载。生产环境中推荐分层组合策略:
7.1 分层架构设计
┌─────────────────────────────────────────────────────────┐
│ AI 推理集群(分层) │
├─────────────────────────────────────────────────────────┤
│ Tier 1: MIG 实例(生产租户) │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ 2g.10gb│ │ 3g.20gb│ │ 1g.5gb │ │ 1g.5gb │ │
│ │ SLA P9 │ │ SLA P9 │ │ SLA P7 │ │ SLA P7 │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ │
│ │
│ Tier 2: Time-Slicing(开发/低优先级) │
│ ┌──────────────────────────────────────────┐ │
│ │ 3g.20gb MIG 实例 × 4 共享 │ │
│ │ batch任务 / A/B 测试 / 离线推理 │ │
│ └──────────────────────────────────────────┘ │
│ │
│ Tier 3: 全卡独占(高价值训练) │
│ ┌──────────────────────────────────────────┐ │
│ │ 全卡直通(不启用 MIG) │ │
│ │ 分布式训练 / 大模型离线推理 │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
实现方式:在节点初始配置时创建异构 MIG Profile(如 1 个 3g.20gb + 3 个 1g.5gb),将 3g.20gb 实例配置为 Time-Slicing(replicas: 4),同时 1g.5gb 实例保持独占。
7.2 自动化的准入控制
通过 Kubernetes 的 ValidatingAdmissionWebhook 实现策略管控:
// mutating-webhook 片段:自动将低优先级 Pod 路由到 Time-Slicing 节点
func assignGPUNode(ctx context.Context, pod *corev1.Pod) error {
labels := map[string]string{
"nvidia.com/mig.config": "all-1g.5gb",
"gpu-sharing-tier": "time-slicing",
}
// 低优先级自动路由到 time-slicing 节点
if pod.Labels["priority-tier"] == "low" {
pod.Spec.NodeSelector = labels
pod.Spec.Tolerations = []corev1.Toleration{
{
Key: "nvidia.com/gpu",
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoSchedule,
},
}
}
return nil
}
八、监控与成本归因
多租户场景下,可观测性和成本分摊是运营刚需:
8.1 DCGM 指标归因
# 为每个 MIG 实例收集指标
dcgmi discovery -l # 列出所有 GPU/MIG 实例
dcgmi dmon -e 1001,1002,1003 -d 1000 # GPU 利用率/显存/温度
# Prometheus exporter 配置
- job_name: 'dcgm-exporter'
static_configs:
- targets: ['dcgm-exporter:9400']
metric_relabel_configs:
- source_labels: [__name__]
regex: 'DCGM_FI_DEV_(.*)'
target_label: 'gpu_metric'
8.2 成本分摊模型
def calculate_gpu_cost(
gpu_type: str,
sharing_model: str,
tenant: str,
usage_hours: float
):
gpu_rates = {
"A100-80GB": {"hourly": 2.85, "power_kw": 0.40},
"H100-80GB": {"hourly": 4.50, "power_kw": 0.70},
}
sharing_multiplier = {
"exclusive": 1.0,
"mig-1g.5gb": 0.14, # ≈ 1/7 卡成本
"mig-2g.10gb": 0.29, # ≈ 2/7 卡成本
"time-slicing-x4": 0.25,
}
cost = (gpu_rates[gpu_type]["hourly"] * usage_hours *
sharing_multiplier.get(sharing_model, 1.0))
return {
"tenant": tenant,
"cost_usd": round(cost, 2),
"model": sharing_model,
}
九、总结与展望
Multi-Tenant GPU 调度没有银弹,正确的决策取决于工作负载特征、隔离需求和成本预算:
- Time-Slicing 适用于开发测试和低密度场景,成本最低但隔离最弱
- MIG 是生产多租户的黄金平衡点,提供硬件级隔离且相对低成本,受限于 A100+ 架构
- vGPU 适用于需要高密度租户和 QoS 保证的场景,但 License 成本较高
未来趋势值得关注:NVIDIA 的 Confidential Computing 架构(H100 CC)将 GPU 信任边界延伸到租户级别,未来可能支持基于 TEE 的 GPU 实例加密隔离;而 CUDA 12.x 引入的 MPS(Multi-Process Service)增强版也在软件层面对提升 Time-Slicing 效率做出改进。
最终建议:以 MIG 为生产基线,用 Time-Slicing 吸纳低优先级负载,配合健全的准入控制和监控归因体系——这是在保证 SLA 前提下最大化 GPU 利用率的务实之道。

发表评论 取消回复