⚠️ 阅读建议:本文是系列第12篇,聚焦Time Slicing时间片轮转方案的原理、配置和最佳实践。如果你还没看过第4篇(MIG+Time Slicing+HAMi全景对比),建议先去了解一下三种GPU共享方案的宏观关系。本篇只深挖Time Slicing这一个方向,把它讲透。
目录
目录
三、Time Slicing vs MIG:软隔离和硬隔离的区别
7.2 Prometheus + DCGM Exporter
一、一个扎心的场景:你的GPU利用率不到30%
先问你一个问题:你们团队的GPU利用率是多少?
别去看云厂商控制台上那个「资源使用率」,它算的是分配率不是利用率。
真实情况是:
大部分开发测试环境的GPU集群,实际算力利用率只有15%-30%。
为什么会这么低?三个原因:
1. 开发环境「申请多、用得少」。 每个开发者怕跑任务的时候被抢占,申请的时候就往大了报。4个开发者的Jupyter Notebook一人独占一张T4,4张卡全占满了,但实际每张卡利用率不到20%。
2. K8s默认不共享GPU。 Kubernetes的Device Plugin原生机制是一张GPU只能分配给一个Pod。要么独占,要么闲着,没有中间态。
3. 开发任务的GPU占用天然碎片化。 调试模型的时候加载一下就停了,改代码去了,GPU在那儿空转。
💡 先算一笔账:
假设你有4张T4(每张大概5000元/月)
独占模式:每张卡只能跑1个Pod → 4个开发者各占1张
实际利用率:平均 20%
有效产出:4 × 20% = 0.8张卡的价值
浪费金额:4 × 5000 × (1 - 20%) = 16,000元/月
如果使用Time Slicing把每张卡切成4份?
Time Slicing模式:1张卡可以跑4个Pod → 4张卡可以跑16个Pod
实际利用率:可以提升到 60%+
同样的GPU数量,服务更多开发者
这就引出了今天的主角——NVIDIA Time Slicing(时间片轮转)。
二、Time Slicing到底是什么?一张图讲清楚
2.1 原理:跟操作系统的「时间片轮转」一模一样
Time Slicing的核心思想非常朴素,你可以在操作系统原理里找到它的祖先。
操作系统让多个进程共享一个CPU的做法是:把CPU时间切成非常小的片(比如10ms),轮流分配给每个进程。
Time Slicing让多个Pod共享一张GPU的做法是:把GPU的执行时间切成片(默认约100ms级别),轮流分配给每个Pod的CUDA任务。
sequenceDiagram
participant k8s as K8s Scheduler
participant DP as Device Plugin
participant Pod1 as Pod A<br/>vLLM推理
participant Pod2 as Pod B<br/>PyTorch训练
participant Pod3 as Pod C<br/>Jupyter调试
participant GPU as GPU (物理卡)
Note over DP: replicas=3<br/>1张卡→3个虚拟资源
k8s->>DP: 查询可用GPU资源
DP->>k8s: nvidia.com/gpu: 3(虚拟上报3个)
Note over Pod1,Pod3: 各自申请 nvidia.com/gpu: 1
loop 时间片轮转(每片 ~100ms)
rect rgb(220, 235, 255)
Note over GPU: 时间片 1 → Pod A
Pod1->>GPU: CUDA Kernel执行中
Pod2-->>GPU: 等待
Pod3-->>GPU: 等待
end
rect rgb(255, 235, 220)
Note over GPU: 时间片 2 → Pod B
Pod1-->>GPU: 等待
Pod2->>GPU: CUDA Kernel执行中
Pod3-->>GPU: 等待
end
rect rgb(220, 255, 235)
Note over GPU: 时间片 3 → Pod C
Pod1-->>GPU: 等待
Pod2-->>GPU: 等待
Pod3->>GPU: CUDA Kernel执行中
end
end
Note over GPU: 循环往复<br/>每个Pod公平获取GPU时间
关键点:同一时刻永远只有一个进程在使用GPU。其他进程的CUDA Kernel被挂起,等轮到自己时再恢复执行。
2.2 Time Slicing到底做了什么?
在K8s层面,Time Slicing实际上只做了一件事:
让nvidia-device-plugin把1张物理GPU「谎报」成N张虚拟GPU。
你设置replicas: 4,Device Plugin就告诉K8s调度器:「这个节点上有4个nvidia.com/gpu设备」。K8s信了,于是4个Pod可以分别申请nvidia.com/gpu: 1并调度到同一张物理卡上。
至于时间片轮转?那是NVIDIA驱动层面的默认行为——多个CUDA进程共享同一张GPU时,驱动自动做时间片调度。Time Slicing只是把这个能力暴露给了K8s。
⚠️ 这里有个巨大的认知偏差需要纠正:
Time Slicing没有在Device Plugin层面做任何「时间调度」。它只是一个资源上报的谎言——把1张卡冒充成N张卡。轮转是NVIDIA驱动自带的机制,不是Time Slicing独有的。
三、Time Slicing vs MIG:软隔离和硬隔离的区别
很多人会混淆Time Slicing和MIG。它们的核心区别用一个类比就能说清楚:
-
MIG(Multi-Instance GPU) = 砌墙分房间。物理上把A100的SM和显存切成独立的小块,每个房间有自己独立的墙、地板、天花板。一个房间着火了(GPU crash),其他房间毫发无损。
-
Time Slicing = 合租共用客厅。所有人都可以在客厅活动,但电视(GPU)一次只能给一个人看。你看的时候别人等着,别人看的时候你等着。而且——所有人的东西(显存)都堆在客厅里,谁都可以用,谁也可以乱放。
graph TB
subgraph MIG["🔒 MIG 硬隔离 —— 砌墙分房间"]
direction TB
MIG_GPU["物理GPU: A100 80GB"]
MIG1["MIG 实例 1<br/>1g.10gb<br/>独立SM + 独立10GB"]
MIG2["MIG 实例 2<br/>2g.20gb<br/>独立SM + 独立20GB"]
MIG3["MIG 实例 3<br/>1g.10gb<br/>独立SM + 独立10GB"]
MIG1 --- MIG_GPU
MIG2 --- MIG_GPU
MIG3 --- MIG_GPU
MIG_GPU_NOTE["✅ 硬件隔离<br/>✅ 显存隔离<br/>✅ 性能隔离<br/>✅ 故障隔离<br/>❌ 仅限 A100/A30/H100"]
end
subgraph TS["⚠️ Time Slicing 软隔离 —— 合租共用客厅"]
direction TB
TS_GPU["物理GPU: 任意NVIDIA GPU"]
TS1["Pod A<br/>nvidia.com/gpu: 1<br/>看到80GB显存"]
TS2["Pod B<br/>nvidia.com/gpu: 1<br/>看到80GB显存"]
TS3["Pod C<br/>nvidia.com/gpu: 1<br/>看到80GB显存"]
TS1 -.->|时间片轮转| TS_GPU
TS2 -.->|时间片轮转| TS_GPU
TS3 -.->|时间片轮转| TS_GPU
TS_GPU_NOTE["❌ 无显存隔离<br/>❌ 无性能隔离<br/>❌ 无故障隔离<br/>✅ 所有GPU都支持<br/>✅ 部署最简单"]
end
classDef mig fill:#d4edda,stroke:#28a745,color:#000
classDef ts fill:#fff3cd,stroke:#ffc107,color:#000
class MIG_GPU_NOTE,mig mig
class TS_GPU_NOTE,ts ts
来,上一张对比表,一看就懂:
| 维度 | Time Slicing(软隔离) | MIG(硬隔离) |
|---|---|---|
| 隔离方式 | 用户态时间片轮转 | 物理SM+显存切分 |
| 显存隔离 | ❌ 不隔离,所有Pod共享全部显存 | ✅ 每实例独立显存 |
| 算力隔离 | ❌ 争抢式,看谁CUDA Kernel多 | ✅ 每实例独立SM |
| 故障隔离 | ❌ 一个OOM整个卡崩 | ✅ 独立ECC、独立重置 |
| 支持的GPU | 所有NVIDIA GPU | 仅A100/A30/H100 |
| 部署复杂度 | 🟢 改ConfigMap即可 | 🔴 需重启GPU、配置MIG |
| 性能损耗 | ~5-20%(上下文切换) | ~5%(L2缓存切分) |
| 动态调整 | ✅ 改replicas重启DP即可 | ❌ 需销毁重建MIG实例 |
| 适用场景 | 开发测试、Jupyter Notebook | 生产环境多租户 |
⚠️ 再强调一次:Time Slicing不做显存隔离,这是它最大的坑,也是它不能上生产的根本原因。
四、Time Slicing配置——完整4步实战
下面开始实战部分。整个过程只需要修改一个ConfigMap重启一个DaemonSet,非常简单。
前置条件
- K8s集群 1.19+
- NVIDIA驱动已安装(确保
nvidia-smi能正常工作) - NVIDIA Container Toolkit已配置
- nvidia-device-plugin(或GPU Operator)已安装
步骤1:创建Time Slicing配置ConfigMap
核心在于replicas参数——你希望一张卡「虚拟」成几张。
# time-slicing-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: time-slicing-config
namespace: gpu-operator # 如果独立部署device plugin,用kube-system
data:
# "any" 表示匹配所有GPU,也可以按GPU型号配置
any: |-
version: v1
flags:
migStrategy: "none" # 必须为none,MIG和Time Slicing互斥
sharing:
timeSlicing:
resources:
- name: nvidia.com/gpu
replicas: 4 # 1张物理卡虚拟成4张
# ⚠️ replicas可以设大一点,但建议不超过4-6
# 设太大后上下文切换开销会指数级上升
# 如果节点有4张卡,总虚拟GPU = 4 × 4 = 16
⚠️ replicas设多大合适?
# 不同场景的推荐replicas值
# 开发环境(Jupyter Notebook、调试):4-6
# 可以塞更多人,反正开发任务GPU占用率低
# 轻量推理服务(BERT、Embedding):2-4
# 推理任务需要相对稳定的延迟
# 训练任务:不要大于2
# 训练一直要算,时间片切太多训练时间指数增长
如果你想按GPU型号分别配置,可以用更细粒度的配置:
# time-slicing-config-by-model.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: time-slicing-config-by-model
namespace: gpu-operator
data:
# 对A100使用不同的replicas
"NVIDIA-A100-SXM4-80GB": |-
version: v1
sharing:
timeSlicing:
resources:
- name: nvidia.com/gpu
replicas: 6
# 对T4用更少的replicas
"NVIDIA-Tesla-T4": |-
version: v1
sharing:
timeSlicing:
resources:
- name: nvidia.com/gpu
replicas: 3
步骤2:将配置挂载到Device Plugin
有两种方式,看你用的是哪种部署方式:
方式A:独立Device Plugin
# nvidia-device-plugin-ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nvidia-device-plugin-daemonset
namespace: kube-system
spec:
selector:
matchLabels:
name: nvidia-device-plugin-ds
template:
metadata:
labels:
name: nvidia-device-plugin-ds
spec:
containers:
- name: nvidia-device-plugin-ctr
image: nvidia/k8s-device-plugin:v0.16.0
args: ["--pass-device-specs", "--device-list-strategy", "volume-mounts"]
# ⚠️ 关键:通过 --config-file 参数指定配置路径
volumeMounts:
- name: config
mountPath: /etc/nvidia/time-slicing-config
# ... 其他挂载和env省略
volumes:
- name: config
configMap:
name: time-slicing-config # 指向步骤1创建的ConfigMap
更新DaemonSet并重启:
kubectl apply -f time-slicing-config.yaml
kubectl apply -f nvidia-device-plugin-ds.yaml
# 等待Pod滚动更新完成
kubectl rollout status daemonset/nvidia-device-plugin-daemonset -n kube-system
方式B:使用GPU Operator(推荐)
GPU Operator管理更自动化,直接在Helm values里配置就行:
# gpu-operator-values.yaml
devicePlugin:
enabled: true
# 使用自定义配置
config:
name: time-slicing-config # ConfigMap名称
default: "any" # 默认使用的配置键
create: true # 自动创建ConfigMap
data:
any: |-
version: v1
flags:
migStrategy: "none"
sharing:
timeSlicing:
resources:
- name: nvidia.com/gpu
replicas: 4
安装或更新GPU Operator:
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update
# 如果是新安装
helm install gpu-operator nvidia/gpu-operator \
--namespace gpu-operator --create-namespace \
--values gpu-operator-values.yaml
# 如果是已有安装
helm upgrade gpu-operator nvidia/gpu-operator \
--namespace gpu-operator \
--values gpu-operator-values.yaml
步骤3:重启Device Plugin
关键一步——必须让Device Plugin重新读取配置。
# 方式1:直接重启DaemonSet的所有Pod
kubectl delete pods -n gpu-operator -l app=nvidia-device-plugin
# 或
kubectl rollout restart daemonset/nvidia-device-plugin-daemonset -n kube-system
# 方式2:等待GPU Operator自动Reconcile(可能需要3-5分钟)
💡 验证配置是否生效:
# 查看节点GPU资源变化
kubectl describe node gpu-node-01 | grep nvidia.com/gpu
# 如果配置正确,你会看到:
# nvidia.com/gpu: 4 ← 原来是1,现在变成4(replicas=4)
# nvidia.com/gpu: 4
# 表示该节点有4个虚拟GPU可供调度
如果节点上有4张物理卡,replicas=4,每个节点应该看到16个nvidia.com/gpu资源。
⚠️ 配置不生效的排查思路:
1. ConfigMap名字对不对? → kubectl get cm -n gpu-operator time-slicing-config
2. ConfigMap的key是不是"any"? → 默认用"any"key
3. Device Plugin有没有读到配置? → 看device plugin日志
4. 节点上的kubelet有没有重启? → 有时需要重启kubelet
# 查看device plugin日志确认配置生效
kubectl logs -n gpu-operator -l app=nvidia-device-plugin --tail=50 | grep -i "time\|sharing\|config"
# 正常输出类似:
# I0709 10:00:00.000000 1 config.go:123] Loading time-slicing config
# I0709 10:00:00.000001 1 config.go:456] Resource "nvidia.com/gpu" replicas: 4
步骤4:提交共享GPU的Pod
配置生效后,提交Pod不再需要特殊标记——K8s调度器看到有4个nvidia.com/gpu资源,你申请1个就分配1个。
# 创建一个测试Pod验证共享GPU
kubectl run gpu-test --image=nvidia/cuda:12.2.0-base-ubuntu22.04 \
--restart=Never --limits="nvidia.com/gpu=1" -- nvidia-smi
# 看Pod运行在哪
kubectl get pod gpu-test -o wide
# 跑多个测试Pod,看它们能不能调度到同一节点
for i in 1 2 3 4; do
kubectl run gpu-test-$i --image=nvidia/cuda:12.2.0-base-ubuntu22.04 \
--restart=Never --limits="nvidia.com/gpu=1" -- nvidia-smi
done
# 查看所有Pod的节点分配
kubectl get pods -l run=gpu-test -o wide
# 正常情况:4个Pod应该都在同一个GPU节点上
五、共享GPU的Pod YAML怎么写?
当Time Slicing配置好之后,Pod的YAML反而变得非常简单——跟你独占GPU时一模一样。
# deploy-dev-inference.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dev-inference
namespace: dev-team-a
labels:
app: inference-dev
team: team-a
spec:
replicas: 2
selector:
matchLabels:
app: inference-dev
template:
metadata:
labels:
app: inference-dev
team: team-a
spec:
containers:
- name: model-server
image: pytorch/pytorch:2.4.0-cuda12.1-cudnn9-runtime
# ⚠️ 跟独占GPU的写法一模一样!
resources:
limits:
nvidia.com/gpu: 1 # K8s不知道这是共享的,它只知道申请1个资源
env:
- name: CUDA_VISIBLE_DEVICES
value: "0"
- name: MODEL_NAME
value: "bert-base-chinese"
- name: CUDA_DEVICE_MAX_CONNECTIONS
value: "1" # 减少并行连接数,降低争抢
ports:
- containerPort: 8000
command: ["python", "-m", "vllm.entrypoints.openai.api_server"]
args:
- "--model"
- "$(MODEL_NAME)"
- "--host"
- "0.0.0.0"
- "--port"
- "8000"
- "--gpu-memory-utilization"
- "0.90"
💡 共享GPU的Pod最佳实践:
# deploy-shared-best-practice.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dev-notebook
namespace: dev-team-b
spec:
replicas: 1
selector:
matchLabels:
app: dev-notebook
template:
metadata:
labels:
app: dev-notebook
spec:
# ⚠️ 关键:使用soft反亲和,让同一个Deployment的副本尽量分散到不同节点
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- dev-notebook
topologyKey: "kubernetes.io/hostname"
containers:
- name: jupyter
image: jupyter/tensorflow-notebook:latest
resources:
limits:
nvidia.com/gpu: 1
# ⚠️ 显存没有硬限制,但可以在应用层做软限制
memory: "32Gi"
cpu: "8"
requests:
# 资源请求设小一点,让调度更灵活
nvidia.com/gpu: 1
memory: "16Gi"
cpu: "4"
env:
- name: NVIDIA_VISIBLE_DEVICES
value: "all"
# ⚠️ 最关键的显存保护!在应用层手动限制
- name: PYTORCH_CUDA_ALLOC_CONF
value: "max_split_size_mb:512" # 减少显存碎片
readinessProbe:
tcpSocket:
port: 8888
initialDelaySeconds: 10
periodSeconds: 5
六、性能影响:上下文切换到底有多亏?
这是Time Slicing最受关注的问题——共享GPU后,每个Pod的性能会下降多少?
6.1 时间片轮转的微观过程
当多个CUDA进程共享GPU时,GPU驱动会进行上下文切换:
上下文切换开销 ≈ 50-200微秒(取决于GPU架构)
完整流程:
1. 进程A的CUDA Kernel执行完毕(或时间片到期)
2. GPU驱动保存A的寄存器状态、L1缓存上下文 ← 切换开销
3. GPU驱动加载B的寄存器状态、L1缓存上下文 ← 切换开销
4. 进程B的CUDA Kernel开始执行
6.2 实测性能数据
根据NVIDIA官方文档和相关测试数据:
| 并行Pod数 | 单Pod吞吐下降 | 延迟增加 | 说明 |
|---|---|---|---|
| 2 | ~10% | 1.5-2x | 少量共享,影响可控 |
| 4 | ~25% | 3-4x | 中度共享,延迟明显增加 |
| 6 | ~40% | 6-8x | 重度共享,不推荐 |
| 8+ | ~60% | 10x+ | 极度共享,基本不可用 |
⚠️ 这里有个反常识的结论:
共享GPU时,GPU计算负载越重,共享效率越低。
原因很简单:
- 轻量推理(如BERT推理):每次CUDA Kernel很小,上下文切换快,共享损失小
- 训练任务(如大模型训练):每次CUDA Kernel很大、很密集,上下文切换频繁,共享损失大
💡 简单判断公式:
训练任务共享GPU的等效速度 ≈ 整卡速度 / (replicas × 1.2)
推理任务共享GPU的等效速度 ≈ 整卡速度 / (replicas × 1.1)
例:replicas=4时
训练:等效 1/(4×1.2) = 21% 整卡性能
推理:等效 1/(4×1.1) = 23% 整卡性能
6.3 一个典型的Time Slicing性能表现
graph LR
subgraph Baseline["基准:独占GPU(replicas=1)"]
B1["BERT推理<br/>吞吐: 1000 req/s<br/>P99延迟: 50ms"]
end
subgraph Shared4["共享模式:replicas=4"]
S1["Pod A<br/>吞吐: 260 req/s<br/>P99: 195ms"]
S2["Pod B<br/>吞吐: 250 req/s<br/>P99: 200ms"]
S3["Pod C<br/>吞吐: 240 req/s<br/>P99: 210ms"]
S4["Pod D<br/>吞吐: 250 req/s<br/>P99: 195ms"]
TOTAL["合计吞吐: ~1000 req/s<br/>单Pod延迟增加 ~4x"]
S1 --> TOTAL
S2 --> TOTAL
S3 --> TOTAL
S4 --> TOTAL
end
style Baseline fill:#d4edda,stroke:#28a745,color:#000
style Shared4 fill:#fff3cd,stroke:#ffc107,color:#000
结论:Time Slicing的总吞吐基本不变(因为GPU的算力总量是固定的),但单个Pod的延迟会大幅增加。这就是为什么——训练任务不适合Time Slicing(训练进程一直跑,延迟飙升),而推理任务相对好一点(推理有空闲期,可以穿插)。
七、监控:如何看到每个Pod的GPU利用率?
Time Slicing一个比较蛋疼的问题是——原生DCGM指标看不到单个Pod的GPU利用率。因为所有Pod用的都是同一张物理卡,DCGM_FI_PROF_GR_ENGINE_ACTIVE只能看到这张卡的总体利用率。
7.1 巧用PID级指标
NVIDIA的DCGM Exporter从v3.0开始支持进程级GPU指标。可以在容器内通过nvidia-smi pmon获取:
# 在Pod内监控该Pod的GPU利用率
nvidia-smi pmon -d 1 -s u
# 输出:
# # gpu pid type sm mem enc dec
# # Idx # Cnt % % % %
# 0 12345 C 25 8 0 0
# 第4列(sm)= SM利用率,第5列(mem)= 显存带宽利用率
7.2 Prometheus + DCGM Exporter
部署DCGM Exporter后,用以下PromQL可以看到整卡的利用率:
# 整卡SM利用率
DCGM_FI_PROF_GR_ENGINE_ACTIVE{gpu="0", job="dcgm-exporter"}
# 按节点聚合
avg by (node) (DCGM_FI_PROF_GR_ENGINE_ACTIVE)
💡 如果想知道每张卡上有几个Pod在共享,可以这样查:
# 通过K8s标签关联GPU指标
# 先查节点上的Pod数量
count by (node) (kube_pod_info{node=~".*gpu.*"})
7.3 更精细的方案:使用NVIDIA SMI实时监控
# 在GPU节点上实时查看进程级GPU使用
watch -n 1 nvidia-smi pmon -s um
# 输出示例:
# # gpu pid type sm mem enc dec command
# # Idx # Cnt % % % % name
# 0 67890 C 35 8 0 0 python3
# 0 67891 C 20 5 0 0 python3
# 0 67892 C 15 3 0 0 python3
# 0 67893 C 10 2 0 0 python3
# ↑ 4个进程共享同一张卡
这就很清楚了——4个Python进程共享一张卡,各自的SM利用率分别是35%、20%、15%、10%。
八、适用场景与限制——为什么生产不推荐
8.1 ✅ 适合用Time Slicing的场景
1. 开发/测试环境 这是最核心的适用场景。开发者在调试模型时,GPU使用是间歇性的——加载模型→跑几个batch→看结果→改代码→再跑。Time Slicing可以让4-6个开发者共享一张卡,大幅降低硬件成本。
2. Jupyter Notebook 数据科学家的Notebook会话同样具有间歇性特征。Time Slicing简单部署,不需要修改Notebook镜像,直接申请nvidia.com/gpu: 1就能用。
3. CI/CD流水线 模型训练CI流水线通常跑几分钟到几十分钟。多个流水线可以共享GPU资源,提高整体利用率。
4. 非A100/A30/H100的GPU V100、T4、A10这些GPU不支持MIG,如果你需要让它们共享,Time Slicing是唯一且最简单的方案。
8.2 ❌ 不适合用Time Slicing的场景
1. 生产环境在线推理服务 实时推理服务对延迟敏感,Time Slicing的时间片轮转会导致P99延迟剧烈波动,不适合。
2. 分布式训练任务 NCCL通信要求所有GPU同时计算和通信。Time Slicing的时间片轮转会打乱NCCL同步,严重降低训练效率。
3. 需要显存保障的任务 如果某个Pod写了个Bug循环分配显存,很快整张卡的80GB就被占满,所有Pod一起OOM。
4. 多租户隔离场景 金融、医疗等合规场景要求租户之间硬件隔离,Time Slicing做不到。
8.3 为什么生产不推荐——一句话说清楚
Time Slicing不保显存、不保延迟、不保故障隔离。三个「不保」加起来,生产环境就是灾难。
具体来说:
# 生产环境出问题的典型场景:
场景1:OOM多米诺骨牌
- Pod A是正常的BERT推理,用了2GB显存
- Pod B是开发者的新模型,加载了70GB参数
- Pod A的推理请求发现显存不够 → OOM被Kill
- 服务中断,用户投诉
场景2:延迟敏感服务被干扰
- 在线推理要求P99 < 100ms
- 另一个Pod在跑大模型训练,一直占着GPU
- 在线推理的请求等了500ms才轮到自己
- 超时报警,SLA不达标
场景3:故障传染
- Pod C的CUDA程序挂了,导致GPU驱动崩溃
- 整张卡不可用,所有Pod同时挂
- 没有故障隔离
九、写在最后:一张表帮你做决策
如果你读完上面这些还在纠结该不该用,这张表直接抄作业:
决策速查
你的GPU是什么?
├── A100/A30/H100
│ ├── 生产环境 → 用 MIG
│ └── 开发测试 → 用 Time Slicing(省事)
│
├── V100/T4/A10(不支持MIG)
│ ├── 需要显存隔离 → 用 HAMi
│ ├── 只是开发调试 → 用 Time Slicing(最简单)
│ └── 生产环境推理 → 用 HAMi
│
└── 消费级显卡(RTX系列)
└── 只能 Time Slicing(且别想上生产)
⚠️ 最终避坑清单
1. 永远记得应用层限显存。 Time Slicing不做显存隔离,你必须在代码里手动设torch.cuda.set_per_process_memory_fraction()。
2. replicas不要超过6。 超过6后上下文切换开销指数增长,GPU算力都浪费在切换上了。
3. 不要跟MIG混用。 Time Slicing要求migStrategy: "none",两者互斥。
4. 监控必须跟上。 没有监控就不知道每个Pod用了多少GPU,出了OOM都不知道谁干的。
5. 接受延迟波动。 给使用Time Slicing的Pod设置合理的超时和重试策略。
一句话总结
Time Slicing是最简单的GPU共享方案,适合开发测试环境快速让更多人用上GPU。但它不做显存隔离、不做性能隔离、不做故障隔离——不要用它跑生产。生产场景老老实实上MIG或者HAMi。
下一篇预告:《混合云AI部署——从IDC到云上GPU的弹性架构》
本地IDC的GPU不够用了怎么办?怎样把本地集群和云上GPU节点做成统一资源池?敏感数据不出域、弹性扩容上云,KubeFed + ClusterAPI的混合云部署方案。我们下周见。
【思考题】 假设你有4张A100(80GB),要服务10个开发者的Jupyter Notebook和2个在线推理服务。你会怎么分配?Time Slicing和MIG可以混用吗?如果不行,你怎么办?欢迎评论区讨论。
【源码获取】 关注本系列,后台回复「time-slicing」获取文中完整YAML配置文件合集。
标签:Time Slicing、GPU共享、nvidia-device-plugin、K8s、开发环境、软隔离、ConfigMap

466

被折叠的 条评论
为什么被折叠?



