推理 GPU 的碎片化治理:小模型合卡与大模型独占策略
一、你的 8×A100 集群 GPU 利用率 35%,但新任务调度不上去——全是碎片
GPU 集群的碎片化问题比 CPU 集群更严重,因为 GPU 的"资源粒度"是整卡。你不能把 0.3 张 A100 分配给一个小模型——最小的分配单元就是 1 张卡。结果就是:集群中每个节点都有 1-2 张空闲卡,但加起来够跑一个新任务,却没有任何单节点有足够的连续空闲卡。
GPU 碎片化的本质是 bin-packing 问题的恶化版。你的集群里混跑了多种规格的推理任务:有的模型只要 1 张 A100(如 7B 参数的 LLaMA),有的要 8 张(如 70B 参数模型做 tensor parallelism)。当这些小任务和大任务混在一个集群里,碎片化是必然结果。
治理策略分两个方向:对小模型用"合卡调度"——多个小模型共享一张 GPU 卡(利用显存隔离和 MIG 机制)。对大模型用"独占节点"——通过节点亲和性和 taint/toleration 把大模型调度到专用节点,不和任何小模型混跑。
二、底层机制与原理剖析
GPU 碎片化治理的核心是在两个方向发力:合卡提高利用率(减少浪费),独占消除碎片(防止切割):
关键技术手段:
MIG (Multi-Instance GPU):NVIDIA A100/H100 支持的最强合卡工具。一张 A100-80GB 可以被切割为最多 7 个独立的 GPU Instance(GI),每个 GI 有独立的显存、缓存和计算单元。这意味着 7 个 7B 模型可以共享一张 A100,每个使用 ~10GB 显存,互不干扰。
MPS (Multi-Process Service):比 MIG 更老的共享方案,允许多个 CUDA 进程共享同一张 GPU 的计算资源。缺点是进程间没有显存隔离——一个进程 OOM 会影响同卡的其他进程。MPS 适合已知资源需求稳定的小模型。
节点独占池:大模型(需要 2-8 张卡做 tensor parallelism)调度到专用节点,节点上不调度任何其他 Pod。通过 K8s 的nodeSelector+toleration+podAntiAffinity实现。
三、生产级代码实现
# 1. MIG 分区配置(在 GPU 节点上执行) # 将 A100-80GB 切割为 3 个 20GB + 2 个 10GB 的分区 # # 生产环境建议在节点初始化时通过 MIG Manager 自动化配置 apiVersion: v1 kind: ConfigMap metadata: name: mig-config namespace: kube-system data: config.yaml: | version: v1 mig-configs: all-1g.10gb: - devices: all mig-enabled: true mig-devices: "1g.10gb": 7 # 7 个 10GB 分区(适合 7B 模型) mixed: - devices: [0,1,2,3] mig-enabled: true mig-devices: "3g.40gb": 1 # 1 个 40GB 分区(70B 模型量化版) "2g.20gb": 2 # 2 个 20GB 分区(13B 模型) --- # 2. 小模型 Pod——使用 MIG 分区 apiVersion: v1 kind: Pod metadata: name: llama-7b-inference labels: app: llama-7b gpu-pool: shared # 标记为共享池 spec: nodeSelector: gpu-pool: shared # 只调度到共享池节点 containers: - name: inference image: vllm/vllm-openai:latest resources: limits: nvidia.com/mig-1g.10gb: 1 # 使用 1 个 MIG 10GB 分区 env: - name: CUDA_VISIBLE_DEVICES value: "0" --- # 3. 大模型 Pod——独占节点 apiVersion: apps/v1 kind: Deployment metadata: name: llama-70b-inference spec: replicas: 1 selector: matchLabels: app: llama-70b template: metadata: labels: app: llama-70b gpu-pool: dedicated # 标记为独占池 spec: # 强制调度到大模型专用节点 nodeSelector: gpu-pool: dedicated nvidia.com/gpu.product: NVIDIA-A100-SXM4-80GB # 反亲和:不与其他大模型共享节点 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: gpu-pool operator: In values: - dedicated topologyKey: kubernetes.io/hostname # 容忍专用节点的 taint tolerations: - key: "gpu-dedicated" operator: "Equal" value: "true" effect: "NoSchedule" containers: - name: inference image: vllm/vllm-openai:latest resources: limits: nvidia.com/gpu: 8 # 独占全部 8 张卡 env: - name: TENSOR_PARALLEL_SIZE value: "8" # 8 卡 Tensor Parallelism节点池管理配置:
# 节点标签和 taint 配置 # 共享池节点 apiVersion: v1 kind: Node metadata: name: gpu-shared-01 labels: gpu-pool: shared nvidia.com/mig.config: all-1g.10gb spec: taints: [] --- # 独占池节点 apiVersion: v1 kind: Node metadata: name: gpu-dedicated-01 labels: gpu-pool: dedicated spec: taints: - key: "gpu-dedicated" value: "true" effect: "NoSchedule"GPU 碎片整理 Descheduler 配置:
# 使用 Descheduler 定期整理 GPU 节点碎片 apiVersion: deskcheduler/v1alpha2 kind: DeschedulerPolicy profiles: - name: gpu-defrag pluginConfig: - name: RemovePodsViolatingNodeAffinity args: nodeAffinityType: - requiredDuringSchedulingIgnoredDuringExecution - name: LowNodeUtilization args: thresholds: nvidia.com/gpu: 20 # GPU 利用率 < 20% cpu: 30 memory: 30 targetThresholds: nvidia.com/gpu: 70 cpu: 70 memory: 70 # 只驱逐低优先级的 Pod # 高优先级生产服务不受影响Go 代码片段——GPU 调度策略决策:
package gpu // GpuSchedulingStrategy 模型到 GPU 池的分配策略 type GpuSchedulingStrategy struct { ModelSize string // "small" / "medium" / "large" VramRequiredGB int // 显存需求 GpuCount int // 需要的 GPU 数量 UseTensorParallelism bool // 是否使用张量并行 } func (s *GpuSchedulingStrategy) RecommendPool() string { // 判断1: 需要多卡 -> 独占池 if s.GpuCount > 1 || s.UseTensorParallelism { return "dedicated" } // 判断2: 显存需求 <= MIG 分区大小 -> 共享池 if s.VramRequiredGB <= 10 { return "shared" } if s.VramRequiredGB <= 20 { return "shared" // 使用 2g.20gb 分区 } // 判断3: 显存需求超过 MIG 最大分区 -> 标准池 return "standard" }四、边界分析与架构权衡
MIG 的限制:
MIG 分区后 GPU 的 CUDA cores、显存带宽、缓存被分割,每个分区的性能不是线性均分的。1g.10gb 分区的 SM(流处理器)数量是全卡的 1/7,某些对 cache 敏感的操作(如大 batch size 的 GEMM)性能下降可能超过 7 倍。另一个限制是:MIG 不支持 P2P(GPU 间直连),如果你的模型需要跨卡通信,不能用 MIG。
节点独占的成本:
独占节点本质上是用一部分 GPU 空闲换取调度确定性和性能隔离。8 卡独占跑一个 70B 模型,如果这个模型的请求不均匀(如夜间低负载),这 8 张卡在低负载时段就是浪费的。需要结合 HPA(水平伸缩)做动态的节点回收——低负载时把备用节点释放回共享池。
适用边界:
最适合 GPU 数量 >= 8 的集群,模型种类 >= 3 种,且模型规格差异大(有的 1 卡、有的 8 卡)的场景。也适合多团队共享 GPU 集群的场景——每个团队的模型可以被分配到不同的节点池。
禁用场景:
不适合 GPU 数量 < 4 的小集群——池化后的调度灵活性不够。如果所有模型规格相似(如全都跑 7B 模型),池化的收益不大。NVIDIA A100 以下架构(V100、T4)不支持 MIG,只能用 MPS 做共享。
五、结语
GPU 碎片化治理的核心是分级池化:MIG 分区让多个小模型共享一张卡,节点独占让大模型享有完整的卡间通信带宽。关键约束是 MIG 不支持跨卡通信——需要多卡 tensor parallelism 的模型不能用 MIG,必须独占节点。治理不是一次性的配置,是持续的组合优化——节点池的容量需要根据模型规模和流量模式动态调整。