GPU 共享与隔离
深入理解 GPU 资源的多租户共享技术,从硬件分区到软件虚拟化
本章目标
- 理解 GPU 共享的核心挑战
- 掌握 MIG (Multi-Instance GPU) 原理与实践
- 了解 vGPU 虚拟化技术
- 学会各种 GPU 共享方案的选型
1. GPU 共享的挑战
1.1 为什么需要 GPU 共享
┌─────────────────────────────────────────────────────────────────────┐
│ GPU 资源利用现状 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 问题场景: │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 推理服务 A │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ GPU 0 (A100 80GB) │ │ │
│ │ │ ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 使用率: 15% │ │ │
│ │ │ 显存使用: 8GB / 80GB │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 推理服务 B │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ GPU 1 (A100 80GB) │ │ │
│ │ │ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 使用率: 8% │ │ │
│ │ │ 显存使用: 4GB / 80GB │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 问题: │
│ - 每个 GPU 价值数万美元,但利用率极低 │
│ - 显存大量空闲 │
│ - 计算单元未充分利用 │
│ - 无法将多个小任务合并到一个 GPU │
│ │
│ 期望: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ GPU 0 (A100 80GB) - 共享使用 │ │
│ │ ████████████████████████░░░░░░░░ 使用率: 80% │ │
│ │ ┌────────────────┐ ┌────────────────┐ ┌──────────────┐ │ │
│ │ │ 服务 A (25GB) │ │ 服务 B (20GB) │ │ 服务 C (15GB)│ │ │
│ │ └────────────────┘ └────────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
1.2 GPU 共享的技术挑战
┌─────────────────────────────────────────────────────────────────────┐
│ GPU 共享核心挑战 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 显存隔离 │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ GPU 显存是全局共享的物理资源 │ │
│ │ - 进程 A 可以访问进程 B 的显存吗? (安全问题) │ │
│ │ - 进程 A 能用完所有显存吗? (公平问题) │ │
│ │ - 如何实现显存配额限制? │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ 2. 计算隔离 │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ SM (Streaming Multiprocessor) 是计算单元 │ │
│ │ - 如何分配 SM 给不同进程? │ │
│ │ - 一个进程的密集计算会影响其他进程吗? (QoS 问题) │ │
│ │ - 时间片轮转 vs 空间分区? │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ 3. 错误隔离 │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ GPU 错误 (如 CUDA kernel 崩溃) 的影响范围 │ │
│ │ - 一个进程崩溃会影响其他进程吗? │ │
│ │ - ECC 错误如何处理? │ │
│ │ - 如何实现故障隔离? │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ 4. 性能干扰 │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 共享资源竞争导致的性能问题 │ │
│ │ - PCIe 带宽竞争 │ │
│ │ - 显存带宽竞争 │ │
│ │ - L2 Cache 竞争 │ │
│ │ - Tensor Core 调度冲突 │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
1.3 GPU 共享技术分类
┌─────────────────────────────────────────────────────────────────────┐
│ GPU 共享技术分类 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 硬件级别 │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ MIG (Multi-Instance GPU) │ │ │
│ │ │ - NVIDIA A100/H100 专有 │ │ │
│ │ │ - 硬件分区,完全隔离 │ │ │
│ │ │ - 支持 1-7 个实例 │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ SR-IOV (vGPU) │ │ │
│ │ │ - 虚拟化层面的 GPU 分割 │ │ │
│ │ │ - 需要特殊驱动和许可证 │ │ │
│ │ │ - 主要用于 VDI 场景 │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 软件级别 │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ MPS (Multi-Process Service) │ │ │
│ │ │ - NVIDIA 官方支持 │ │ │
│ │ │ - 时分复用 + 空间复用 │ │ │
│ │ │ - 适合多进程共享 │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ 时分复用 (Time Slicing) │ │ │
│ │ │ - 最简单的共享方式 │ │ │
│ │ │ - 轮流使用 GPU │ │ │
│ │ │ - 无隔离保证 │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ 显存虚拟化 (GPU 共享框架) │ │ │
│ │ │ - 阿里 cGPU / 腾讯 qGPU / NVIDIA vGPU │ │ │
│ │ │ - 软件层面限制显存使用 │ │ │
│ │ │ - 配合调度器实现 │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
2. MIG (Multi-Instance GPU) 深入解析
2.1 MIG 架构原理
┌─────────────────────────────────────────────────────────────────────┐
│ MIG 硬件架构 (A100 示例) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 完整 A100 GPU (108 SM, 80GB HBM2e) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ GPC 0 │ GPC 1 │ GPC 2 │ GPC 3 │ ... │ │ │
│ │ │ (14 SM) │ (14 SM) │ (14 SM) │ (14 SM) │ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ L2 Cache (40 MB) │ │ │
│ │ │ 被分成 8 个独立的 Memory Slice │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ HBM2e (80GB) │ │ │
│ │ │ 被分成 8 个独立的 Memory Partition (每个 10GB) │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ MIG 分区后 (示例: 3 个实例) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │
│ │ │ MIG 3g.40gb │ │ MIG 2g.20gb │ │ MIG 2g.20gb │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ 42 SM │ │ 28 SM │ │ 28 SM │ │ │
│ │ │ 40GB 显存 │ │ 20GB 显存 │ │ 20GB 显存 │ │ │
│ │ │ 4 Mem Slice │ │ 2 Mem Slice │ │ 2 Mem Slice │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ 完全隔离 │ │ 完全隔离 │ │ 完全隔离 │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ MIG 隔离保证: │
│ ✓ 显存隔离: 每个实例有独立的显存分区 │
│ ✓ 计算隔离: 每个实例有独立的 SM │
│ ✓ 缓存隔离: 每个实例有独立的 L2 Cache 分区 │
│ ✓ 带宽隔离: 每个实例有独立的显存带宽 │
│ ✓ 错误隔离: 一个实例的错误不影响其他实例 │
│ │
└─────────────────────────────────────────────────────────────────────┘
2.2 MIG 配置规格
# A100 MIG Profile 配置 (完整)
# Profile 命名规则: <compute_slices>g.<memory_slices*5>gb
# compute_slices: GPU Instance 中的计算切片数 (1-7)
# memory_slices: 每个 memory slice = 5GB (A100 40GB) 或 10GB (A100 80GB)
# A100-80GB 可用的 MIG Profile:
┌────────────────┬──────────┬─────────────┬────────────┬───────────────┐
│ Profile │ SM 数量 │ 显存 (GB) │ 内存带宽 │ 最大实例数 │
├────────────────┼──────────┼─────────────┼────────────┼───────────────┤
│ 7g.80gb │ 98 │ 80 │ 100% │ 1 │
│ 4g.40gb │ 56 │ 40 │ 50% │ 1 │
│ 3g.40gb │ 42 │ 40 │ 50% │ 2 │
│ 2g.20gb │ 28 │ 20 │ 25% │ 3 │
│ 1g.10gb │ 14 │ 10 │ 12.5% │ 7 │
│ 1g.10gb+me │ 14 │ 10 (扩展) │ 12.5% │ 1 │
│ 1g.20gb │ 14 │ 20 │ 25% │ 4 │
└────────────────┴──────────┴─────────────┴────────────┴───────────────┘
# H100 MIG Profile (H100-80GB):
┌────────────────┬──────────┬─────────────┬───────────────┐
│ Profile │ SM 数量 │ 显存 (GB) │ 最大实例数 │
├────────────────┼──────────┼─────────────┼───────────────┤
│ 7g.80gb │ 132 │ 80 │ 1 │
│ 4g.40gb │ 66 │ 40 │ 1 │
│ 3g.40gb │ 60 │ 40 │ 2 │
│ 2g.20gb │ 42 │ 20 │ 3 │
│ 1g.10gb │ 22 │ 10 │ 7 │
└────────────────┴──────────┴─────────────┴───────────────┘
2.3 MIG 操作实战
# 1. 检查 GPU 是否支持 MIG
nvidia-smi -q | grep "MIG Mode"
# Current : Disabled
# Pending : Disabled
# 查看支持 MIG 的 GPU
nvidia-smi --query-gpu=name,mig.mode.current --format=csv
# name, mig.mode.current
# NVIDIA A100-SXM4-80GB, Disabled
# 2. 启用 MIG 模式
sudo nvidia-smi -i 0 -mig 1
# Warning: MIG mode change requires a GPU reset.
# 重置 GPU (需要停止所有使用 GPU 的进程)
sudo nvidia-smi -i 0 -r
# 验证 MIG 已启用
nvidia-smi -i 0 --query-gpu=mig.mode.current --format=csv
# mig.mode.current
# Enabled
# 3. 查看可用的 GPU Instance Profile
nvidia-smi mig -lgip
# +-----------------------------------------------------------------------------+
# | GPU instance profiles: |
# | GPU Name ID Instances Memory P2P SM DEC ENC |
# | Free/Total GiB CE JPEG OFA |
# |=============================================================================|
# | 0 MIG 1g.10gb 19 7/7 9.50 No 14 0 0 |
# | 1 0 0 |
# | 0 MIG 1g.10gb+me 20 1/1 9.50 No 14 1 0 |
# | 1 1 1 |
# | 0 MIG 2g.20gb 14 3/3 19.50 No 28 1 0 |
# | 2 0 0 |
# | 0 MIG 3g.40gb 9 2/2 39.25 No 42 2 0 |
# | 3 0 0 |
# | 0 MIG 4g.40gb 5 1/1 39.25 No 56 2 0 |
# | 4 0 0 |
# | 0 MIG 7g.80gb 0 1/1 79.00 No 98 5 0 |
# | 7 1 1 |
# +-----------------------------------------------------------------------------+
# 4. 创建 GPU Instance (GI)
# 创建 2 个 3g.40gb 实例
sudo nvidia-smi mig -cgi 9,9 -C
# 或者指定不同大小
# 创建 1 个 3g.40gb + 2 个 2g.20gb
sudo nvidia-smi mig -cgi 9 -C
sudo nvidia-smi mig -cgi 14,14 -C
# 5. 查看创建的实例
nvidia-smi mig -lgi
# +-------------------------------------------------------+
# | GPU instances: |
# | GPU Name Profile Instance Placement |
# | ID ID Start:Size |
# |=======================================================|
# | 0 MIG 3g.40gb 9 1 0:4 |
# | 0 MIG 2g.20gb 14 2 4:2 |
# | 0 MIG 2g.20gb 14 3 6:2 |
# +-------------------------------------------------------+
# 6. 在每个 GI 中创建 Compute Instance (CI)
nvidia-smi mig -lci
# 查看可用的 CI profile
# 创建 CI (一般使用默认配置)
sudo nvidia-smi mig -cci
# 7. 查看完整的 MIG 配置
nvidia-smi
# 会显示 MIG 设备,每个设备有独立的 UUID
# 8. 使用 MIG 实例 (通过 UUID)
# 获取 MIG UUID
nvidia-smi -L
# GPU 0: NVIDIA A100-SXM4-80GB (UUID: GPU-xxxxxx)
# MIG 3g.40gb Device 0: (UUID: MIG-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
# MIG 2g.20gb Device 1: (UUID: MIG-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
# MIG 2g.20gb Device 2: (UUID: MIG-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
# 在容器中使用特定 MIG 实例
docker run --gpus '"device=MIG-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"' \
nvidia/cuda:12.0-base nvidia-smi
# 或使用索引 (MIG 设备按顺序编号)
docker run --gpus '"device=0:0"' nvidia/cuda:12.0-base nvidia-smi # 第一个 MIG 设备
docker run --gpus '"device=0:1"' nvidia/cuda:12.0-base nvidia-smi # 第二个 MIG 设备
# 9. 销毁 MIG 实例
# 先销毁 CI
sudo nvidia-smi mig -dci
# 再销毁 GI
sudo nvidia-smi mig -dgi
# 10. 禁用 MIG 模式
sudo nvidia-smi -i 0 -mig 0
sudo nvidia-smi -i 0 -r # 重置 GPU
2.4 MIG 与 Kubernetes 集成
# NVIDIA Device Plugin 配置 MIG 策略
# /etc/nvidia-device-plugin/config.yaml
version: v1
sharing:
mig:
strategy: single # single, mixed, none
# single: 假设所有 GPU 都启用 MIG,暴露 MIG 设备
# mixed: 支持 MIG 和非 MIG GPU 混合
# none: 忽略 MIG 设备
---
# Pod 使用 MIG 设备
apiVersion: v1
kind: Pod
metadata:
name: mig-pod
spec:
containers:
- name: cuda-container
image: nvidia/cuda:12.0-base
command: ["nvidia-smi"]
resources:
limits:
# 请求特定的 MIG Profile
nvidia.com/mig-3g.40gb: 1
# 或
# nvidia.com/mig-2g.20gb: 1
# nvidia.com/mig-1g.10gb: 1
# MIG 配置管理器 (自动配置 MIG)
# nvidia-mig-manager
apiVersion: v1
kind: ConfigMap
metadata:
name: mig-parted-config
namespace: nvidia-device-plugin
data:
config.yaml: |
version: v1
mig-configs:
# 默认配置: 7 个 1g.10gb
all-1g.10gb:
- devices: all
mig-enabled: true
mig-devices:
"1g.10gb": 7
# 混合配置: 1 个 3g.40gb + 2 个 2g.20gb
mixed:
- devices: [0]
mig-enabled: true
mig-devices:
"3g.40gb": 1
"2g.20gb": 2
# 大实例配置
big-instance:
- devices: all
mig-enabled: true
mig-devices:
"7g.80gb": 1
2.5 MIG 性能特征
┌─────────────────────────────────────────────────────────────────────┐
│ MIG 性能分析 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ A100-80GB 不同 Profile 的性能对比 (以 1g.10gb 为基准) │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Profile │ SM │ 显存带宽 │ FP16 算力 │ 相对性能 │ │
│ ├──────────────┼──────┼──────────┼─────────────┼───────────────┤ │
│ │ 7g.80gb │ 98 │ 2039GB/s │ 312 TFLOPS │ 7x │ │
│ │ 4g.40gb │ 56 │ 1020GB/s │ 179 TFLOPS │ 4x │ │
│ │ 3g.40gb │ 42 │ 1020GB/s │ 134 TFLOPS │ 3x │ │
│ │ 2g.20gb │ 28 │ 510GB/s │ 90 TFLOPS │ 2x │ │
│ │ 1g.10gb │ 14 │ 255GB/s │ 45 TFLOPS │ 1x (基准) │ │
│ └──────────────┴──────┴──────────┴─────────────┴───────────────┘ │
│ │
│ 性能隔离测试: │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 场景: 3 个 MIG 2g.20gb 实例同时运行 ResNet-50 推理 │ │
│ │ │ │
│ │ 实例 1 ████████████████████ 1200 img/s │ │
│ │ 实例 2 ████████████████████ 1180 img/s │ │
│ │ 实例 3 ████████████████████ 1190 img/s │ │
│ │ │ │
│ │ 每个实例性能稳定,互不影响 │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ MIG vs 时分复用 对比: │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 时分复用 (3 个进程共享一个 GPU): │ │
│ │ 进程 1 ████░░░░████░░░░████░░░░ 平均: 400 img/s │ │
│ │ 进程 2 ░░░░████░░░░████░░░░████ 平均: 400 img/s │ │
│ │ 进程 3 ░░░░░░░░████░░░░████░░░░ 平均: 400 img/s │ │
│ │ (有明显的延迟抖动) │ │
│ │ │ │
│ │ MIG (3 个 2g.20gb 实例): │ │
│ │ MIG 1 ████████████████████████ 稳定: 1200 img/s │ │
│ │ MIG 2 ████████████████████████ 稳定: 1180 img/s │ │
│ │ MIG 3 ████████████████████████ 稳定: 1190 img/s │ │
│ │ (无延迟抖动,性能隔离) │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
3. MPS (Multi-Process Service)
3.1 MPS 原理
┌─────────────────────────────────────────────────────────────────────┐
│ MPS 架构原理 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 没有 MPS 的情况 (默认): │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 进程 A 进程 B 进程 C │ │
│ │ │ │ │ │ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │CUDA │ │CUDA │ │CUDA │ 每个进程独立 │ │
│ │ │Context│ │Context│ │Context│ 的 CUDA 上下文 │ │
│ │ └─────┘ └─────┘ └─────┘ │ │
│ │ │ │ │ │ │
│ │ └───────────────┼───────────────┘ │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │ GPU │ 时分复用: A→B→C→A→B→C... │ │
│ │ │ │ 上下文切换开销大 │ │
│ │ └──────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ 使用 MPS 的情况: │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 进程 A 进程 B 进程 C │ │
│ │ │ │ │ │ │
│ │ └───────────────┼───────────────┘ │ │
│ │ ▼ │ │
│ │ ┌──────────────┐ │ │
│ │ │ MPS Server │ │ │
│ │ │ │ 共享 CUDA Context │ │
│ │ │ ┌──────────┐ │ 合并 kernel 调度 │ │
│ │ │ │ CUDA │ │ │ │
│ │ │ │ Context │ │ │ │
│ │ │ └──────────┘ │ │ │
│ │ └──────┬───────┘ │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │ GPU │ 空间复用: A+B+C 并行执行 │ │
│ │ │ │ 无上下文切换开销 │ │
│ │ └──────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ MPS 优势: │
│ ✓ 减少上下文切换开销 │
│ ✓ 更好的 SM 利用率 (空间复用) │
│ ✓ 支持 Hyper-Q (多硬件队列) │
│ │
│ MPS 限制: │
│ ✗ 无显存隔离 (共享地址空间) │
│ ✗ 无错误隔离 (一个进程崩溃影响所有) │
│ ✗ 需要特殊配置 │
│ │
└─────────────────────────────────────────────────────────────────────┘
3.2 MPS 配置与使用
# 1. 启动 MPS Server
export CUDA_VISIBLE_DEVICES=0
export CUDA_MPS_PIPE_DIRECTORY=/tmp/nvidia-mps
export CUDA_MPS_LOG_DIRECTORY=/tmp/nvidia-mps-log
# 创建目录
mkdir -p $CUDA_MPS_PIPE_DIRECTORY
mkdir -p $CUDA_MPS_LOG_DIRECTORY
# 启动控制守护进程
nvidia-cuda-mps-control -d
# 验证 MPS 运行
echo "get_server_list" | nvidia-cuda-mps-control
# 输出: Server process ID: XXXXX
# 2. 在容器中使用 MPS
docker run --gpus all \
-v /tmp/nvidia-mps:/tmp/nvidia-mps \
-e CUDA_MPS_PIPE_DIRECTORY=/tmp/nvidia-mps \
nvidia/cuda:12.0-base \
python my_app.py
# 3. 设置每个客户端的资源限制
# 限制每个 MPS 客户端使用的 SM 百分比
echo "set_default_active_thread_percentage 50" | nvidia-cuda-mps-control
# 或者针对特定客户端
echo "set_active_thread_percentage <server_pid> 50" | nvidia-cuda-mps-control
# 限制每个 MPS 客户端的显存
# (需要 CUDA 11.4+)
echo "set_default_device_pinned_mem_limit 0 4G" | nvidia-cuda-mps-control
# 设置 GPU 0 每个客户端最多使用 4GB 显存
# 4. 查看 MPS 状态
nvidia-smi
# 会显示 MPS 相关进程
echo "get_server_list" | nvidia-cuda-mps-control
echo "ps -ef" | nvidia-cuda-mps-control
# 5. 关闭 MPS
echo "quit" | nvidia-cuda-mps-control
3.3 MPS 在 Kubernetes 中使用
# 部署 MPS Server 作为 DaemonSet
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nvidia-mps-server
namespace: kube-system
spec:
selector:
matchLabels:
name: nvidia-mps-server
template:
metadata:
labels:
name: nvidia-mps-server
spec:
nodeSelector:
nvidia.com/gpu: "true"
containers:
- name: mps-server
image: nvidia/cuda:12.0-base
command:
- nvidia-cuda-mps-control
- "-d"
securityContext:
privileged: true
env:
- name: CUDA_MPS_PIPE_DIRECTORY
value: /tmp/nvidia-mps
- name: CUDA_MPS_LOG_DIRECTORY
value: /tmp/nvidia-mps-log
volumeMounts:
- name: mps-pipe
mountPath: /tmp/nvidia-mps
- name: mps-log
mountPath: /tmp/nvidia-mps-log
volumes:
- name: mps-pipe
hostPath:
path: /tmp/nvidia-mps
- name: mps-log
hostPath:
path: /tmp/nvidia-mps-log
---
# 使用 MPS 的 Pod
apiVersion: v1
kind: Pod
metadata:
name: mps-client
spec:
containers:
- name: cuda-app
image: my-cuda-app
env:
- name: CUDA_MPS_PIPE_DIRECTORY
value: /tmp/nvidia-mps
volumeMounts:
- name: mps-pipe
mountPath: /tmp/nvidia-mps
resources:
limits:
nvidia.com/gpu: 1 # 仍然需要声明 GPU
volumes:
- name: mps-pipe
hostPath:
path: /tmp/nvidia-mps
4. 时分复用 (Time Slicing)
4.1 时分复用原理
┌─────────────────────────────────────────────────────────────────────┐
│ 时分复用工作原理 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 时间轴 │
│ ─────────────────────────────────────────────────────────────► │
│ │
│ ┌───────┬───────┬───────┬───────┬───────┬───────┬───────┐ │
│ │ Pod A │ Pod B │ Pod C │ Pod A │ Pod B │ Pod C │ Pod A │ ... │
│ └───────┴───────┴───────┴───────┴───────┴───────┴───────┘ │
│ │<- 时间片 ->│ │
│ │
│ 特点: │
│ - 多个 Pod 轮流使用同一个 GPU │
│ - 每个 Pod 在其时间片内独占 GPU │
│ - 上下文切换开销较大 │
│ - 延迟不可预测 (需等待其他 Pod 完成时间片) │
│ │
│ 适用场景: │
│ ✓ 开发测试环境 │
│ ✓ 批处理任务 (不关心延迟) │
│ ✓ 低 GPU 利用率的工作负载 │
│ ✗ 实时推理服务 (延迟敏感) │
│ ✗ 需要 QoS 保证的场景 │
│ │
└─────────────────────────────────────────────────────────────────────┘
4.2 Kubernetes 时分复用配置
# nvidia-device-plugin 配置时分复用
# /etc/nvidia-device-plugin/config.yaml
version: v1
sharing:
timeSlicing:
renameByDefault: false # 是否重命名资源为 nvidia.com/gpu.shared
failRequestsGreaterThanOne: false # 是否允许请求多个共享 GPU
resources:
- name: nvidia.com/gpu
replicas: 4 # 每个 GPU 可以被 4 个 Pod 共享
---
# 重新部署 device plugin
kubectl delete -f nvidia-device-plugin.yaml
kubectl apply -f nvidia-device-plugin.yaml
# 验证可用 GPU 数量增加
kubectl describe node | grep nvidia.com/gpu
# nvidia.com/gpu: 8 # 原来 2 个 GPU,现在变成 8 个 (2*4)
# Pod 使用共享 GPU
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod-1
spec:
containers:
- name: cuda-container
image: nvidia/cuda:12.0-base
command: ["nvidia-smi", "-l", "10"]
resources:
limits:
nvidia.com/gpu: 1 # 请求 1 个共享 GPU 份额
---
# 同一节点上可以调度多个 Pod 使用同一 GPU
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod-2
spec:
containers:
- name: cuda-container
image: nvidia/cuda:12.0-base
resources:
limits:
nvidia.com/gpu: 1 # 与 gpu-pod-1 共享同一 GPU
5. vGPU 虚拟化
5.1 vGPU 架构
┌─────────────────────────────────────────────────────────────────────┐
│ NVIDIA vGPU 架构 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 虚拟机层 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ VM 1 │ │ VM 2 │ │ VM 3 │ │ VM 4 │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ vGPU 驱动 │ │ vGPU 驱动 │ │ vGPU 驱动 │ │ vGPU 驱动 │ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │
│ │ └─────────────┼─────────────┼─────────────┘ │ │
│ │ ▼ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ Hypervisor 层 │ │
│ ┌─────────────────────┼───────────────────────────────────────┐ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ vGPU Manager │ │ │
│ │ │ │ │ │
│ │ │ - 管理 vGPU 实例的创建和销毁 │ │ │
│ │ │ - 调度 GPU 资源给各 VM │ │ │
│ │ │ - 强制执行 vGPU Profile 限制 │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ESXi / KVM / Xen │ │ │
│ └─────────────────────┼───────────────────────────────────────┘ │
│ ▼ │
│ 物理层 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ NVIDIA GPU (支持 vGPU) │ │ │
│ │ │ │ │ │
│ │ │ 支持的 GPU: │ │ │
│ │ │ - NVIDIA A100, A30, A16, A10, A2 │ │ │
│ │ │ - NVIDIA RTX 6000, RTX 4000 │ │ │
│ │ │ - Tesla V100, T4 │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ vGPU 类型: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ vPC : 虚拟 PC,用于 VDI │ │
│ │ vCS : 虚拟计算服务器,用于 AI/ML │ │
│ │ vWS : 虚拟工作站,用于专业图形 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
5.2 vGPU Profile 示例
# A100-40GB vGPU Profile 示例
┌────────────────────┬───────────────┬───────────────┬───────────────┐
│ vGPU Profile │ 显存 (GB) │ 最大 vGPU 数 │ 使用场景 │
├────────────────────┼───────────────┼───────────────┼───────────────┤
│ A100-4C │ 4 │ 10 │ 推理 │
│ A100-5C │ 5 │ 8 │ 推理 │
│ A100-8C │ 8 │ 5 │ 推理/小训练 │
│ A100-10C │ 10 │ 4 │ 训练 │
│ A100-20C │ 20 │ 2 │ 大模型训练 │
│ A100-40C │ 40 │ 1 │ 完整 GPU │
└────────────────────┴───────────────┴───────────────┴───────────────┘
# 查看可用 vGPU 类型 (在 ESXi 或 KVM 主机上)
# ESXi:
esxcli graphics vgpu list
# KVM (使用 mdev):
ls /sys/class/mdev_bus/*/mdev_supported_types/
5.3 vGPU vs MIG 对比
┌─────────────────────────────────────────────────────────────────────┐
│ vGPU vs MIG 对比 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────┬────────────────────┬────────────────────┐ │
│ │ 特性 │ vGPU │ MIG │ │
│ ├───────────────────┼────────────────────┼────────────────────┤ │
│ │ 虚拟化层级 │ Hypervisor 层 │ 硬件层 │ │
│ ├───────────────────┼────────────────────┼────────────────────┤ │
│ │ 隔离级别 │ 时分复用 │ 硬件分区 │ │
│ │ │ (软件隔离) │ (完全隔离) │ │
│ ├───────────────────┼────────────────────┼────────────────────┤ │
│ │ 性能隔离 │ 有干扰 │ 完全隔离 │ │
│ ├───────────────────┼────────────────────┼────────────────────┤ │
│ │ 错误隔离 │ 部分隔离 │ 完全隔离 │ │
│ ├───────────────────┼────────────────────┼────────────────────┤ │
│ │ 显存分配 │ 灵活配置 │ 固定 Profile │ │
│ ├───────────────────┼────────────────────┼────────────────────┤ │
│ │ 许可证 │ 需要 (付费) │ 不需要 │ │
│ ├───────────────────┼────────────────────┼────────────────────┤ │
│ │ 支持 GPU │ 多种 GPU │ A100/H100 等 │ │
│ ├───────────────────┼────────────────────┼────────────────────┤ │
│ │ 实例数上限 │ 最多 32 个 │ 最多 7 个 │ │
│ ├───────────────────┼────────────────────┼────────────────────┤ │
│ │ 使用场景 │ VDI、虚拟化环境 │ 容器、Kubernetes │ │
│ └───────────────────┴────────────────────┴────────────────────┘ │
│ │
│ 选型建议: │
│ - 需要完全隔离 + Kubernetes → MIG │
│ - 已有虚拟化基础设施 → vGPU │
│ - 需要更多实例数 → vGPU │
│ - 成本敏感 → MIG (无许可证费用) │
│ │
└─────────────────────────────────────────────────────────────────────┘
6. GPU 共享框架
6.1 阿里云 cGPU
┌─────────────────────────────────────────────────────────────────────┐
│ 阿里云 cGPU 架构 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 容器层 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │
│ │ │ Container A │ │ Container B │ │ Container C │ │ │
│ │ │ 显存: 4GB │ │ 显存: 8GB │ │ 显存: 4GB │ │ │
│ │ │ 算力: 25% │ │ 算力: 50% │ │ 算力: 25% │ │ │
│ │ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │ │
│ │ └──────────────────┼──────────────────┘ │ │
│ └─────────────────────────────┼───────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ cGPU Runtime │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ 拦截层 (LD_PRELOAD / GPU API Hook) │ │ │
│ │ │ │ │ │
│ │ │ - 拦截 CUDA Driver API 调用 │ │ │
│ │ │ - 显存分配限制 (cuMemAlloc 等) │ │ │
│ │ │ - 算力配额管理 │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ 调度器 │ │ │
│ │ │ │ │ │
│ │ │ - 跨容器调度 GPU 时间片 │ │ │
│ │ │ - 算力 QoS 保证 │ │ │
│ │ │ - 显存超卖管理 │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ NVIDIA GPU │ │
│ │ (物理共享) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ cGPU 特点: │
│ ✓ 支持显存隔离 (软件层面) │
│ ✓ 支持算力隔离 (时分复用) │
│ ✓ 兼容所有 NVIDIA GPU │
│ ✓ 与 Kubernetes 深度集成 │
│ ✗ 非硬件隔离,有一定性能开销 │
│ │
└─────────────────────────────────────────────────────────────────────┘
6.2 开源 GPU 共享方案
# HAMi (Heterogeneous AI Computing Virtualization Middleware)
# https://github.com/Project-HAMi/HAMi
# 部署 HAMi
kubectl apply -f https://raw.githubusercontent.com/Project-HAMi/HAMi/master/deployments/hami.yaml
# Pod 使用共享 GPU
apiVersion: v1
kind: Pod
metadata:
name: hami-pod
spec:
containers:
- name: cuda-container
image: nvidia/cuda:12.0-base
resources:
limits:
nvidia.com/gpu: 1
nvidia.com/gpumem: 4096 # 限制显存 4GB
nvidia.com/gpucores: 50 # 限制算力 50%
---
# GPU Share Scheduler Extender (阿里开源)
# https://github.com/AliyunContainerService/gpushare-scheduler-extender
# 安装
kubectl apply -f https://raw.githubusercontent.com/AliyunContainerService/gpushare-scheduler-extender/master/deploy/gpushare-schd-extender.yaml
# Pod 使用
apiVersion: v1
kind: Pod
metadata:
name: gpushare-pod
spec:
schedulerName: gpushare-scheduler
containers:
- name: cuda-container
image: nvidia/cuda:12.0-base
resources:
limits:
aliyun.com/gpu-mem: 4 # 请求 4GB 显存
7. GPU 共享方案选型
7.1 方案对比
┌─────────────────────────────────────────────────────────────────────────────────┐
│ GPU 共享方案对比 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────┬──────────────┬──────────────┬──────────────┬──────────────┐ │
│ │ │ MIG │ MPS │ 时分复用 │ cGPU/HAMi │ │
│ ├────────────┼──────────────┼──────────────┼──────────────┼──────────────┤ │
│ │ 隔离级别 │ 硬件完全隔离 │ 共享上下文 │ 时间片隔离 │ 软件隔离 │ │
│ ├────────────┼──────────────┼──────────────┼──────────────┼──────────────┤ │
│ │ 显存隔离 │ ✓ 完全隔离 │ ✗ 无隔离 │ ✗ 无隔离 │ ✓ 软件限制 │ │
│ ├────────────┼──────────────┼──────────────┼──────────────┼──────────────┤ │
│ │ 算力隔离 │ ✓ 固定分配 │ △ 有限 │ ✗ 轮流使用 │ △ 软件调度 │ │
│ ├────────────┼──────────────┼──────────────┼──────────────┼──────────────┤ │
│ │ 性能损耗 │ 几乎无 │ 低 │ 中等 │ 低-中 │ │
│ ├────────────┼──────────────┼──────────────┼──────────────┼──────────────┤ │
│ │ 延迟稳定性 │ ✓ 稳定 │ △ 一般 │ ✗ 抖动大 │ △ 一般 │ │
│ ├────────────┼──────────────┼──────────────┼──────────────┼──────────────┤ │
│ │ GPU 兼容性 │ A100/H100 │ 大多数 GPU │ 所有 GPU │ 所有 GPU │ │
│ ├────────────┼──────────────┼──────────────┼──────────────┼──────────────┤ │
│ │ 复杂度 │ 中 │ 低 │ 低 │ 中-高 │ │
│ ├────────────┼──────────────┼──────────────┼──────────────┼──────────────┤ │
│ │ 成本 │ 无额外成本 │ 无额外成本 │ 无额外成本 │ 取决于实现 │ │
│ └────────────┴──────────────┴──────────────┴──────────────┴──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
7.2 场景选型指南
┌─────────────────────────────────────────────────────────────────────┐
│ GPU 共享场景选型 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 在线推理服务 (低延迟、高 QoS) │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ 推荐: MIG ││
│ │ 原因: ││
│ │ - 硬件隔离保证延迟稳定性 ││
│ │ - 一个实例故障不影响其他服务 ││
│ │ - 显存和算力完全隔离 ││
│ │ ││
│ │ 配置示例: ││
│ │ A100-80GB → 7 个 1g.10gb 实例,每个服务一个实例 ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ 2. 开发测试环境 (成本优先) │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ 推荐: 时分复用 + HAMi ││
│ │ 原因: ││
│ │ - 最大化 GPU 利用率 ││
│ │ - 开发测试对延迟不敏感 ││
│ │ - 配置简单 ││
│ │ ││
│ │ 配置示例: ││
│ │ 1 个 GPU 共享给 4-8 个开发者 ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ 3. 批处理训练任务 │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ 推荐: 独占 GPU + 弹性调度 ││
│ │ 原因: ││
│ │ - 训练任务通常需要较多显存 ││
│ │ - 可以通过任务调度提高利用率 ││
│ │ - 显存共享可能导致 OOM ││
│ │ ││
│ │ 配置示例: ││
│ │ 使用 Kubernetes Job + 优先级调度 ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ 4. 多模型推理 (显存密集) │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ 推荐: MIG (大实例) 或 cGPU ││
│ │ 原因: ││
│ │ - 多个模型需要可预测的显存 ││
│ │ - 需要显存配额管理 ││
│ │ ││
│ │ 配置示例: ││
│ │ A100-80GB → 2 个 3g.40gb 实例 ││
│ │ 或 cGPU 分配: 模型 A 20GB + 模型 B 20GB + 模型 C 20GB ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ 5. VDI 虚拟桌面 │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ 推荐: vGPU ││
│ │ 原因: ││
│ │ - 与虚拟化平台深度集成 ││
│ │ - 支持更多实例数 ││
│ │ - 成熟的图形工作站支持 ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────────┘
7.3 生产环境最佳实践
# 综合使用多种共享策略
# 根据工作负载类型自动选择
# 1. Node 标签标识 GPU 类型和共享模式
kubectl label node node1 nvidia.com/gpu.sharing=mig
kubectl label node node2 nvidia.com/gpu.sharing=timeslice
kubectl label node node3 nvidia.com/gpu.sharing=none # 独占
# 2. 使用 Node Affinity 调度
apiVersion: v1
kind: Pod
metadata:
name: inference-pod
labels:
workload-type: inference
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: nvidia.com/gpu.sharing
operator: In
values:
- mig # 推理服务使用 MIG 节点
containers:
- name: inference
image: my-inference-service
resources:
limits:
nvidia.com/mig-2g.20gb: 1
---
apiVersion: v1
kind: Pod
metadata:
name: dev-pod
labels:
workload-type: development
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: nvidia.com/gpu.sharing
operator: In
values:
- timeslice # 开发环境使用时分复用节点
containers:
- name: dev
image: nvidia/cuda:12.0-devel
resources:
limits:
nvidia.com/gpu: 1
---
# 3. 训练任务独占 GPU
apiVersion: batch/v1
kind: Job
metadata:
name: training-job
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: nvidia.com/gpu.sharing
operator: In
values:
- none # 训练使用独占节点
containers:
- name: training
image: my-training-job
resources:
limits:
nvidia.com/gpu: 4 # 使用 4 个完整 GPU
restartPolicy: Never
8. 本章总结
8.1 核心知识点
┌─────────────────────────────────────────────────────────────────────┐
│ GPU 共享与隔离知识图谱 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 核心挑战 │
│ ├── 显存隔离: 软件限制 vs 硬件分区 │
│ ├── 计算隔离: 时分复用 vs 空间分区 │
│ ├── 错误隔离: 共享上下文 vs 独立实例 │
│ └── 性能干扰: 资源竞争、带宽争用 │
│ │
│ MIG (硬件级别) │
│ ├── 支持 GPU: A100, H100, A30 │
│ ├── Profile: 1g.10gb ~ 7g.80gb │
│ ├── 隔离级别: 显存 + 计算 + 缓存 + 带宽 │
│ ├── 操作命令: nvidia-smi mig -cgi/-dgi/-lgi │
│ └── K8s 集成: nvidia.com/mig-Xg.Xgb │
│ │
│ MPS (软件级别) │
│ ├── 原理: 共享 CUDA Context,合并 kernel 调度 │
│ ├── 优势: 减少上下文切换,支持空间复用 │
│ ├── 限制: 无显存隔离,无错误隔离 │
│ └── 使用: nvidia-cuda-mps-control │
│ │
│ 时分复用 │
│ ├── 原理: 多进程轮流使用 GPU │
│ ├── K8s: nvidia-device-plugin timeSlicing 配置 │
│ ├── 适用: 开发测试、批处理 │
│ └── 限制: 延迟抖动、无隔离保证 │
│ │
│ 选型原则 │
│ ├── 推理服务 → MIG (延迟稳定) │
│ ├── 开发测试 → 时分复用 (成本低) │
│ ├── 批处理 → 独占 + 弹性调度 │
│ └── VDI → vGPU (虚拟化集成) │
│ │
└─────────────────────────────────────────────────────────────────────┘
8.2 面试要点
MIG 和时分复用的区别是什么?
- MIG: 硬件分区,完全隔离 (显存/计算/缓存/带宽)
- 时分复用: 软件调度,轮流使用,无隔离保证
- MIG 适合需要 QoS 保证的场景,时分复用适合开发测试
什么场景应该使用 MIG?
- 在线推理服务 (需要低延迟、稳定性)
- 多租户共享 (需要隔离)
- 故障隔离要求高的场景
MPS 的优缺点是什么?
- 优点: 减少上下文切换开销,支持空间复用
- 缺点: 无显存隔离,一个进程崩溃影响所有进程
如何在 Kubernetes 中实现 GPU 共享?
- MIG: 配置 nvidia-device-plugin 的 mig strategy
- 时分复用: 配置 timeSlicing replicas
- 软件方案: HAMi、gpushare-scheduler-extender
8.3 下一章预告
下一章我们将深入探讨 GPU 监控与调试技术:
- nvidia-smi 深入解析
- DCGM (Data Center GPU Manager)
- GPU 性能分析工具
- 常见 GPU 问题排查