成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

提升GPU利用率:探索NVIDIA的MIG與MPS虛擬化技術

云計算 虛擬化
對于像V100這樣的GPU,有些廠商會讓多個用戶來共用一張GPU,從而降低單個用戶的費用。在共享GPU過程中,一個重要的操作就是虛擬化,但是虛擬化在安全問題、服務質量上面還有較大的進步空間。

1. 背景

目前GPU卡資源緊張且業務需求逐漸遞增,存在整卡不夠分配或GPU利用率低造成資源浪費的情況。

我們也不可否認還有非常多的應用場景對算力的需求不大,比如:

  • AI推理場景,基本都是在線實時計算,要求延時低,batchsize小,計算量不大。
  • AI開發機場景,團隊內部共享GPU,對算力要求低。

這些場景的分布非常廣泛,在這些場景下,AI應用是無法把GPU強大的計算能力全部發揮出來的。所以,長期以來,很多用戶的GPU利用率都不高,基本都只有10%-30%。

GPU的切分(虛擬化)需求基本來自于兩個方面,一個是普通消費者,二個是計算/服務中心。

對于普通消費者(用戶),希望使用到新推出的GPU特性,比如某些高性能的CUDA操作,而這些操作只有高版本的硬件SM才具備;同時,很多情況下消費者并不能用滿一整張顯卡(比如V100或者A100)的所有資源;另外“數據中心”類的GPU產品,價格都比較高(V100、A100都是wRMB為單位)。所以消費者在使用、價格方面有小資源高性能的GPU需求。

某購物平臺上面的GPU價格某購物平臺上面的GPU價格

對于服務廠商(比如云服務),一方面需要提供價格便宜、性能穩定的GPU給用戶使用。由于整卡的成本價格高,所以服務費用(租金)不會太低。另一個方面,大型的計算中心需要管理成千上萬的GPU,服務廠商有提升集群利用率的訴求,小規格的GPU資源能夠提升配置的細粒度,從而能夠更好的提升集群GPU利用率。

目前,對于像V100這樣的GPU,有些廠商會讓多個用戶來共用一張GPU,從而降低單個用戶的費用。在共享GPU過程中,一個重要的操作就是虛擬化,但是虛擬化在安全問題、服務質量上面還有較大的進步空間。

2. GPU Share策略方案

①MIG(MULTI-INSTANCEGPU****)

隨著AMPERE架構的發布,NVIDIA推出了劃時代的產品–A100,性能達到前所未有的高度。從性能壓榨的角度講,普通的一個AI應用要想把全部A100性能發揮出來是很難的。反過來說,大量資源沒用上,閑置就是浪費。

因此,MIG(multi-Instance GPU)就這樣應運而生了。

MIG 打破了原有 GPU 資源的分配方式,能夠基于 A100 從硬件層面把一個GPU切分成最多 7 個 GPU 實例,并且可以使每一個 GPU 實例都能夠擁有各自的 SMs 和內存系統。簡單理解就是現在可以并發的同時跑7個不同的AI應用,最大程度把強大的GPU資源全部用上。

由于是基于硬件切分的方式,MIG可以讓每個GPU實例之間的內存空間訪問互不干擾,保障每一個使用者的工作時延和吞吐量都是可預期的。

imgimg

由于采用的是硬切分的方式,GPU實例之間的隔離度很好,但是靈活度就比較受限了。MIG的切分方式,每個GPU實例的大小只能按照固定的profile來切分:

imgimg

這個表格清晰的展示了各種不同大小的 GPU 實例他們具備的流處理器比例、內存比例、以及可以分配的數量。

各種profile的組合方式也是非常有限的,如下圖所示:

imgimg

②MPS(MULTI-PROCESS SERVICE )

MPS,包含在CUDA工具包中的多進程服務。它是一組可以替換的,二進制兼容的CUDA API實現,包括3個模塊:

  • 守護進程,用于啟動或停止MPS服務進程, 同時也負責為用戶進程和服務進程之間建立連接關系
  • 服務進程, 多個用戶在單個GPU上面的共享連接,為多個用戶之間執行并發的服務
  • 用戶運行時,集成在CUDA driver庫中,對于CUDA應用程序來說,調用過程透明

當用戶希望在多進程條件下發揮GPU的并發能力,就可以使用MPS。MPS允許多個進程共享同一個GPU context。這樣可以避免上下文切換造成的額外的開銷,以及串行化執行帶來的時間線拉長。同時,MPS還允許不同進程的kernel和memcpy操作在同一GPU上并發執行,以實現最大化GPU利用率 。

具體可以用下面2個圖片對比來說明MPS的特點。

首先,在沒有開啟MPS的情況下,有兩個進程A(藍色)和B(紅色),每個進程都有自己的CUDA context。從圖中可以看到,兩個進程雖然同時被發送,但是在實際執行中是被串行執行的,兩個進程會被GPU中的時間片輪轉調度機制輪流調度進GPU進行執行。這就是執行的時間線被拉長的原因。

imgimg

繼續往下看,如果我們開啟了MPS,同樣是啟動兩個進程A(藍色)和B(紅色),MPS服務進程會將它們兩個CUDA context融合到一個CUDA context里面。這就是最大的不同。兩個context融合到一個之后,GPU上不存在context輪轉切換,減少額外開銷;而且從時間片上來看的話,進程A和B的函數是真正的實現了并發執行的。這就是MPS帶來的好處。

imgimg

MPS的好處是顯而易見的,可以提升GPU利用率,減少GPU上下文切換時間、減少GPU上下文存儲空間。總的來說,就是可以充分利用GPU資源。那么,這么好的技術,為什么在業界用得很少呢?

因為MPS的context融合方式會帶來一個嚴重的問題:錯誤會互相影響。一個進程錯誤退出(包括被kill),如果該進程正在執行kernel,那么和該進程共同share IPC和UVM的其他進程也會一同出錯退出。因此無法在生產場景上大規模使用。

一個節點只能指定一種GPU Share策略

GPU Share策略

說明

備注

MPS

多個進程或應用程序共享同一個GPU的資源,適用于需要并行處理大量數據或執行復雜計算任務的應用場景。

單卡均分;可指定一個節點中多少張卡進行拆分;備注:均分份數—》拆分卡數GPU:1/4 * NVIDIA Ampere A100顯存:1/4 * 24GB 或 6GB

MIG

在一個物理GPU上同時運行多個獨立的GPU實例,不會相互干擾。

支持每個卡都可以指定一種MIG策略;單卡:排序固定,最多7切分:7*14+2+14+1+1+1...img NVIDIA Ampere A100(3g.40gb)

GPU卡型

MIG(僅支持A系列、H系列的卡型)

NVIDIA Ampere A800(80G)

7 * (1g.10gb)4 * (1g.20gb)3 * (2g.20gb)2 * (3g.40gb)1 * (4g.40gb)1 * (7g.80gb)1 * (1g.12gb)、1 * (2g.24gb)、1 * (3g.47gb)2 * (1g.10gb)、1 * (2g.20gb)、1 * (3g.40gb)

NVIDIA Ampere 4090(24G)

不支持

NVIDIA Ampere A100(40G)

7 * (1g.5gb)3 * (2g.10gb)2 * (3g.20gb)1* (4g.20gb)1 * (7g.40gb)

NVIDIA Ampere A30(24G)

4 * (1g.6gb)2 * (2g.12gb)1 * (4g.24gb)2 * (1g.6gb)、1 * (2g.12gb)

NVIDIA GeForce 3090

不支持

3. 實踐與測試

方案一(MPS)

源自nvidia官方開源項目 https://github.com/nvidia/k8s-device-plugin

nvidia-device-plugin 支持兩種gpu-share的方式,分別為 “時間片” 和 “mps”,二者不兼容,只能二選其一。

  1. 時間片方案:應用可以完整使用GPU內存,各應用采用時間片的方式共享GPU計算能力,各應用間內存不隔離(直接放棄這個方案)。
  2. MPS方案:GPU卡被MPS DAEMON 托管,按照拆分SHARE的副本數,均分GPU memory,應用使用GPU memory超過均分值后 OOM,各個進程間GPU memory隔離,GPU的計算能力也按照比例拆分(還是基于時間片的)。

相對而言,MPS方案在隔離性和資源分配方面更具優勢,本次驗證主要做MPS的,沒有做時間片的。

支持的粒度:可以支持到單節點級別,只對某個節點開啟MPS或者時間片的SHARE。

啟用MPS操作

安裝nvidia-device-plugin的時候,啟用第二配置,默認配置不開啟mps或者時間片,在第二配置中啟用gpu-share。

nvidia-device-plugin 支持到具體節點開啟mps,如果某個節點需要開啟MPS,需要在節點上打對應標簽開啟。

nvidia.com/mps.capable 決定是否在節點啟用MPS, 例如:true

nvidia.com/device-plugin.config 決定當前節點使用的配置名字。例如:config1

理論上配置個數是沒限制的,單集群下,可以做多個配置,例如 nvidia-share-4,nvidia-share-2,按照不同的業務需求,對不同的節點按照不同比例拆分。

一個完整的部署編排yaml實例如下(yaml中的節點親和性和容忍,按需修改即可):

---
# Source: nvidia-device-plugin/templates/service-account.yml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nvidia-device-plugin-service-account
  namespace: kube-system
  labels:
    helm.sh/chart: nvidia-device-plugin-0.15.0-rc.2
    app.kubernetes.io/name: nvidia-device-plugin
    app.kubernetes.io/version: "0.15.0-rc.2"
    app.kubernetes.io/managed-by: Helm
---
# Source: nvidia-device-plugin/templates/configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nvidia-device-plugin-configs
  namespace: kube-system
  labels:
    helm.sh/chart: nvidia-device-plugin-0.15.0-rc.2
    app.kubernetes.io/name: nvidia-device-plugin

    app.kubernetes.io/version: "0.15.0-rc.2"
    app.kubernetes.io/managed-by: Helm
data:
  config0: |-
    version: v1

  config1: |-
    version: v1
    sharing:
      mps:
        renameByDefault: true
        resources:
        - name: nvidia.com/gpu
          replicas: 2
---
# Source: nvidia-device-plugin/templates/role.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nvidia-device-plugin-role
  namespace: kube-system
  labels:
    helm.sh/chart: nvidia-device-plugin-0.15.0-rc.2
    app.kubernetes.io/name: nvidia-device-plugin

    app.kubernetes.io/version: "0.15.0-rc.2"
    app.kubernetes.io/managed-by: Helm
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
---
# Source: nvidia-device-plugin/templates/role-binding.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: nvidia-device-plugin-role-binding
  namespace: kube-system
  labels:
    helm.sh/chart: nvidia-device-plugin-0.15.0-rc.2
    app.kubernetes.io/name: nvidia-device-plugin
    app.kubernetes.io/version: "0.15.0-rc.2"
    app.kubernetes.io/managed-by: Helm
subjects:
  - kind: ServiceAccount
    name: nvidia-device-plugin-service-account
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: nvidia-device-plugin-role
  apiGroup: rbac.authorization.k8s.io
---
# Source: nvidia-device-plugin/templates/daemonset-device-plugin.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin
  namespace: kube-system
  labels:
    helm.sh/chart: nvidia-device-plugin-0.15.0-rc.2
    app.kubernetes.io/name: nvidia-device-plugin
    app.kubernetes.io/version: "0.15.0-rc.2"
    app.kubernetes.io/managed-by: Helm
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: nvidia-device-plugin
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app.kubernetes.io/name: nvidia-device-plugin
      annotations:
        checksum/config: 5cae25ed78745124db43b014773455550cf9c60962da45074548790b2acb66f0
    spec:
      priorityClassName: system-node-critical
      securityContext:
        {}
      serviceAccountName: nvidia-device-plugin-service-account
      shareProcessNamespace: true
      initContainers:
      - image: nvcr.io/nvidia/k8s-device-plugin:v0.17.1
        name: nvidia-device-plugin-init
        command: ["config-manager"]
        env:
        - name: ONESHOT
          value: "true"
        - name: KUBECONFIG
          value: ""
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: "spec.nodeName"
        - name: NODE_LABEL
          value: "nvidia.com/device-plugin.config"
        - name: CONFIG_FILE_SRCDIR
          value: "/available-configs"
        - name: CONFIG_FILE_DST
          value: "/config/config.yaml"
        - name: DEFAULT_CONFIG
          value: "config0"
        - name: FALLBACK_STRATEGIES
          value: "named,single"
        - name: SEND_SIGNAL
          value: "false"
        - name: SIGNAL
          value: ""
        - name: PROCESS_TO_SIGNAL
          value: ""
        volumeMounts:
          - name: available-configs
            mountPath: /available-configs
          - name: config
            mountPath: /config
      containers:
      - image: nvcr.io/nvidia/k8s-device-plugin:v0.17.1
        name: nvidia-device-plugin-sidecar
        command: ["config-manager"]
        env:
        - name: ONESHOT
          value: "false"
        - name: KUBECONFIG
          value: ""
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: "spec.nodeName"
        - name: NODE_LABEL
          value: "nvidia.com/device-plugin.config"
        - name: CONFIG_FILE_SRCDIR
          value: "/available-configs"
        - name: CONFIG_FILE_DST
          value: "/config/config.yaml"
        - name: DEFAULT_CONFIG
          value: "config0"
        - name: FALLBACK_STRATEGIES
          value: "named,single"
        - name: SEND_SIGNAL
          value: "true"
        - name: SIGNAL
          value: "1" # SIGHUP
        - name: PROCESS_TO_SIGNAL
          value: "nvidia-device-plugin"
        volumeMounts:
          - name: available-configs
            mountPath: /available-configs
          - name: config
            mountPath: /config
        securityContext:
          capabilities:
            add:
              - SYS_ADMIN
      - image: nvcr.io/nvidia/k8s-device-plugin:v0.17.1
        imagePullPolicy: IfNotPresent
        name: nvidia-device-plugin-ctr
        command: ["nvidia-device-plugin"]
        env:
          - name: MPS_ROOT
            value: "/run/nvidia/mps"
          - name: CONFIG_FILE
            value: /config/config.yaml
          - name: NVIDIA_MIG_MONITOR_DEVICES
            value: all
          - name: NVIDIA_VISIBLE_DEVICES
            value: all
          - name: NVIDIA_DRIVER_CAPABILITIES
            value: compute,utility
        securityContext:
          capabilities:
            add:
              - SYS_ADMIN
        volumeMounts:
          - name: device-plugin
            mountPath: /var/lib/kubelet/device-plugins
          # The MPS /dev/shm is needed to allow for MPS daemon health-checking.
          - name: mps-shm
            mountPath: /dev/shm
          - name: mps-root
            mountPath: /mps
          - name: cdi-root
            mountPath: /var/run/cdi
          - name: available-configs
            mountPath: /available-configs
          - name: config
            mountPath: /config
      volumes:
        - name: device-plugin
          hostPath:
            path: /var/lib/kubelet/device-plugins
        - name: mps-root
          hostPath:
            path: /run/nvidia/mps
            type: DirectoryOrCreate
        - name: mps-shm
          hostPath:
            path: /run/nvidia/mps/shm
        - name: cdi-root
          hostPath:
            path: /var/run/cdi
            type: DirectoryOrCreate
        - name: available-configs
          configMap:
            name: "nvidia-device-plugin-configs"
        - name: config
          emptyDir: {}
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: nvidia.com/gpu.present
                operator: In
                values:
                - "true"
      tolerations:
        - key: CriticalAddonsOnly
          operator: Exists
        - effect: NoSchedule
          key: nvidia.com/gpu
          operator: Exists
---
# Source: nvidia-device-plugin/templates/daemonset-mps-control-daemon.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin-mps-control-daemon
  namespace: kube-system
  labels:
    helm.sh/chart: nvidia-device-plugin-0.15.0-rc.2
    app.kubernetes.io/name: nvidia-device-plugin
    app.kubernetes.io/version: "0.15.0-rc.2"
    app.kubernetes.io/managed-by: Helm
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: nvidia-device-plugin
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app.kubernetes.io/name: nvidia-device-plugin
      annotations:
        checksum/config: 5cae25ed78745124db43b014773455550cf9c60962da45074548790b2acb66f0
    spec:
      priorityClassName: system-node-critical
      securityContext:
        {}
      serviceAccountName: nvidia-device-plugin-service-account
      shareProcessNamespace: true
      initContainers:
      - image: nvcr.io/nvidia/k8s-device-plugin:v0.17.1
        name: mps-control-daemon-mounts
        command: [mps-control-daemon, mount-shm]
        securityContext:
          privileged: true
        volumeMounts:
        - name: mps-root
          mountPath: /mps
          mountPropagation: Bidirectional
      - image: nvcr.io/nvidia/k8s-device-plugin:v0.17.1
        name: mps-control-daemon-init
        command: ["config-manager"]
        env:
        - name: ONESHOT
          value: "true"
        - name: KUBECONFIG
          value: ""
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: "spec.nodeName"
        - name: NODE_LABEL
          value: "nvidia.com/device-plugin.config"
        - name: CONFIG_FILE_SRCDIR
          value: "/available-configs"
        - name: CONFIG_FILE_DST
          value: "/config/config.yaml"
        - name: DEFAULT_CONFIG
          value: "config0"
        - name: FALLBACK_STRATEGIES
          value: "named,single"
        - name: SEND_SIGNAL
          value: "false"
        - name: SIGNAL
          value: ""
        - name: PROCESS_TO_SIGNAL
          value: ""
        volumeMounts:
          - name: available-configs
            mountPath: /available-configs
          - name: config
            mountPath: /config
      containers:
        # TODO: How do we synchronize the plugin and control-daemon on restart.
        - image: nvcr.io/nvidia/k8s-device-plugin:v0.17.1
          name: mps-control-daemon-sidecar
          command: ["config-manager"]
          env:
          - name: ONESHOT
            value: "false"
          - name: KUBECONFIG
            value: ""
          - name: NODE_NAME
            valueFrom:
              fieldRef:
                fieldPath: "spec.nodeName"
          - name: NODE_LABEL
            value: "nvidia.com/device-plugin.config"
          - name: CONFIG_FILE_SRCDIR
            value: "/available-configs"
          - name: CONFIG_FILE_DST
            value: "/config/config.yaml"
          - name: DEFAULT_CONFIG
            value: "config0"
          - name: FALLBACK_STRATEGIES
            value: "named,single"
          - name: SEND_SIGNAL
            value: "true"
          - name: SIGNAL
            value: "1"
          - name: PROCESS_TO_SIGNAL
            value: "/usr/bin/mps-control-daemon"
          volumeMounts:
            - name: available-configs
              mountPath: /available-configs
            - name: config
              mountPath: /config
        - image: nvcr.io/nvidia/k8s-device-plugin:v0.17.1
          imagePullPolicy: IfNotPresent
          name: mps-control-daemon-ctr
          command: [mps-control-daemon]
          env:
          - name: NODE_NAME
            valueFrom:
              fieldRef:
                apiVersion: v1
                fieldPath: spec.nodeName
          - name: CONFIG_FILE
            value: /config/config.yaml
          - name: NVIDIA_MIG_MONITOR_DEVICES
            value: all
          - name: NVIDIA_VISIBLE_DEVICES
            value: all
          - name: NVIDIA_DRIVER_CAPABILITIES
            value: compute,utility
          securityContext:
            privileged: true
          volumeMounts:
          - name: mps-shm
            mountPath: /dev/shm
          - name: mps-root
            mountPath: /mps
          - name: available-configs
            mountPath: /available-configs
          - name: config
            mountPath: /config
      volumes:
      - name: mps-root
        hostPath:
          path: /run/nvidia/mps
          type: DirectoryOrCreate
      - name: mps-shm
        hostPath:
          path: /run/nvidia/mps/shm
      - name: available-configs
        configMap:
          name: "nvidia-device-plugin-configs"
      - name: config
        emptyDir: {}
      nodeSelector:
        # We only deploy this pod if the following sharing label is applied.
        nvidia.com/mps.capable: "true"
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: nvidia.com/gpu.present
                operator: In
                values:
                - "true"
      tolerations:
        - key: CriticalAddonsOnly
          operator: Exists
        - effect: NoSchedule
          key: nvidia.com/gpu
          operator: Exists

驗證

我們的測試集群只有一個節點,有8張4090卡,單卡GPU Memory為 24G。我們采用MPS方案,將卡副本SHARE為兩份,理論上集群節點上看到的 nvidia.com/gpu.shared 資源為16個,單個資源的可用GPU Memory為12G左右。

  • 部署yaml到集群

imgimg

img

部署成功,節點資源如預期,GPU卡的兩倍(因為我們之SHARE了2)。

  • 部署一個使用shared資源的容器(它只能使用一個shared設備)

imgimg

img

部署成功。

  • 驗證GPU MEMORY

初始狀態

imgimg

由于理論上線為12G,我們這兒創建 (1024, 1024, 1024) 類型為fp32的tensor的size為 4G

為了不超過12G,測試 (1024, 1024, 1024) * 2 + (1024,1024,512)理論上不會OOM;

為了達到12G,測試(1024, 1024, 1024) * 3 就應該OOM。

  • (1024,1024,1024) * 2 + (1024,1024,1024)結果,如預期。

imgimg

  • (1024, 1024, 1024) * 3,結果如預期。

imgimg

性能

測試腳本

import torch
import time

# size of tensor
w = 10000000

def compute_pi(n):
    count = 0
    total =  n // w
    print(f"total is {total}")
    for idx in range(total):
        print(f"{idx}/{total}")
        x = torch.rand(w, device='cuda') * 2 - 1
        y = torch.rand(w, device='cuda') * 2 - 1
        distance = x**2 + y **2
        count += (distance <= 1).sum().item()
    return 4 * count / n

n = w * 100000
s = time.time()
pi = compute_pi(n)
e = time.time()

print(f"total {e - s}")
print(f"pi is {pi}")

測試方案: 直接在主機上,在沒有開啟MPS的卡上先后進行多進程并行計算和多進程串行計算,得到計算時間。

再在mps的卡上,進行同樣的計算,對比兩種方案的計算耗時。

在測試機器上(4090顯卡)開啟mps后,同時在一個卡上執行測試腳本,分別看兩個實例同時執行腳本的耗時和單獨執行的耗時,進行對比結果。

  • 在開啟MPS的卡上,兩個進程并行計算。

實例1,計算用時 193 秒

imgimg

實例2,計算用時 193秒

img

GPU使用率,可以看到GPU開啟MPS之后是 Exclusive 模式,GPU利用率 100%

imgimg

  • 在開啟MPS的卡上,串行運行計算任務(就是兩個任務先后計算)

實例1,計算耗時74秒

imgimg

實例2, 計算耗時74秒

imgimg

GPU使用率截圖

imgimg

  • 在沒開啟MPS的卡上,進行并行計算

實例1,用時188秒

imgimg

實例2,用時188秒

imgimg

  • 串行計算,耗時71秒

img

結論:開啟MPS的性能影響不大,開啟后193 ,未開啟188, 性能損失 = 2%

適用場景
  1. 小模型
  2. 計算量不是很大,QPS不是很高的情況下。
卡級別的MPS開啟

目前官方nvidia-device-plugin沒有支持單機上指定卡開啟mps,(場景,單機8卡,四卡開MPS,四卡獨占),源代碼中,可以看到有多種resource的支持,但是參數被屏蔽了,另外就是單配置多資源的情況下,會開啟多個mps daemon,導致nvidia-device-plugin容器不能正常運行。

針對這個問題,進行了單獨的適配,目前已經支持了卡級別MPS的開啟。需要更多大規模的測試后,再投入生產。

方案二(VGPU)

來自第四范式的vgpu方案,目前volcano(要求版本>=1.8.0)集成的也是它。 https://github.com/Project-HAMi/HAMi

其目的是為了統一算力卡的虛擬化調度,正在集成華為vNPU(這個ISSUE),值得調研和投入。

方案三(MIG)

如何管理MIG,參考了知乎(https://zhuanlan.zhihu.com/p/558046644),其中如果關注資源利用率,可以看看 vgpu 和 mig-vgpu部分的吞吐量,性能對比部分。 MIG由gi和ci組成,gi表示gpu實例,ci表示算力單元。

拆分MIG操作流程

MIG的shell操作主要包括:查看命令、創建命令和刪除命令。MIG的操作都要用root權限,所以如果是非root用戶,操作命令要加上sudo字符,下面操作示例中默認用戶是root。 首先將這些操作例出來,然后對一些創建與刪除操作進行講解。

功能

命令

說明

【開】指定某卡 開啟MIG

nvidia-smi -i 0 -mig 1

-i 指定的GPU編號 可以是0,1,3

【關】指定某卡 關閉MIG

nvidia-smi -i 0 -mig 0


【開】全部卡的MIG使能

nvidia-smi -mig 1

1 打開; 0 關閉;

【查看】子GPU實例的profile

nvidia-smi mig -lgip

獲得子GPU可創建的情況

【查看】子GPU實例的placement

nvidia-smi mig -lgipp

獲得子GPU可以創建的位置

【查看】子GPU上CI的profile

nvidia-smi mig -lcip

添加 -gi指定特定的子GPU,如指定子GPU 2查看上面的CI實例: nvidia-smi mig -lci -gi 2

【查看】已創建的子GPU的情況

nvidia-smi mig -lgi


【創建】子GPU + 對應的CI

nvidia-smi mig -i 0 -cgi 9 -C

-i: 指定父GPU -cgi:列出需要創建的子GPU的類型 格式:9 或者 3g.20gb 或者 MIG 3g.20gb -C :連同一起創建CI

【創建】子GPU

nvidia-smi mig -i 0 -cgi 9

創建一個profile為9的GI實例: 3個計算單元 + 20gb顯存。

【創建】子GPU上面的CI

nvidia-smi mig -cci 0,1 -gi 1

-cci:創建的CI實例的編號 -gi:指定子GPU

【刪除】子GPU

nvidia-smi mig -dgi -i 0 -gi 1

-i:指定父GPU -gi:待刪除的子GPU

【刪除】子GPU上面的CI 實例

nvidia-smi mig -dci -i 0 -gi 1 -ci 0

-i:指定父GPU -gi:待操作的子GPU -ci: 待刪除的CI實例

【查看】 整個MIG實例情況

nvidia-smi -L


MIG的操作順序概況為:

使能MIG -> 創建GI實例 -> 創建CI實例 -> 刪除CI實例 -> 刪除GI實例 -> 關閉MIG

imgimg

  • 檢查卡類型 nvidia-smi,卡要求A系列以后
  • 針對單卡開啟MIG,nvidia-smi -i 0 -mig 1,如果出現pending的情況可能需要重啟機器。

imgimg

  • 查看支持的mig profile,nvidia-smi mig -i 0 -lgip

img

  • 這兒我們將0號卡拆成兩個3g.40gb單元 nvidia-smi mig -i 0 -cgi 9,執行兩次,創建了兩。

img

  • 查看創建結果 nvidia-smi mig -i 0 -lgi

imgimg

  • 查看每個GI實例支持的CI規格 nvidia-smi mig -i 0 -lcip

imgimg

  • 給mig實例創建 CI nvidia-smi mig -gi 0 -cci 2

imgimg

  • 查看最終結果 nvidia-smi

imgimg

apiVersion: v1
kind: Pod
metadata:
  name: test1
spec:
  containers:
  - image: harbor.maip.io/base/pytorch-alpaca:v3
    imagePullPolicy: IfNotPresent
    name: test
    command:
    - /bin/bash
    - -c
    - "sleep infinity"
    resources:
      requests:
        nvidia.com/mig-3g.40gb:  1
      limits:
        nvidia.com/mig-3g.40gb:  1
---
apiVersion: v1
kind: Pod
metadata:
  name: test2
spec:
  containers:
  - image: harbor.maip.io/base/pytorch-alpaca:v3
    imagePullPolicy: IfNotPresent
    name: test
    command:
    - /bin/bash
    - -c
    - "sleep infinity"
    resources:
      requests:
        nvidia.com/mig-3g.40gb:  1
      limits:
        nvidia.com/mig-3g.40gb:  1
---
apiVersion: v1
kind: Pod
metadata:
  name: test3
spec:
  containers:
  - image: harbor.maip.io/base/pytorch-alpaca:v3
    imagePullPolicy: IfNotPresent
    name: test
    command:
    - /bin/bash
    - -c
    - "sleep infinity"
    resources:
      requests:
        nvidia.com/gpu:  1
      limits:
        nvidia.com/gpu:  1
  • 看結果

imgimg

imgimgimgimgimgimg

刪除mig 需要先刪除 ci 刪除ci

nvidia-smi mig -dci -i 0 -gi 1 -ci 0 刪除gi nvidia-smi mig -dgi -i 0 -gi 1

4. gpu-operator一鍵部署

GPU Operator 是 NVIDIA 提供的一個 Kubernetes Operator,它簡化了在 Kubernetes 集群中使用 GPU 的過程,通過自動化的方式處理 GPU 驅動程序安裝、NVIDIA Device Plugin、DCGM Exporter 等組件。

helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update
helm install --wait --generate-name \
     -n gpu-operator --create-namespace \
     nvidia/gpu-operator \
     # 如果已經安裝了 NVIDIA 驅動程序,可以在 GPU Operator 中禁用驅動安裝,修改values.yaml
     --set driver.enabled=false
  • 其中mps和mig的配置,需要在values.yaml中devicePlugin和migManager新增,然后創建configmap
devicePlugin:
  enabled: true
  repository: nvcr.io/nvidia
  image: k8s-device-plugin
  version: v0.17.1
  imagePullPolicy: IfNotPresent
  env:
    - name: PASS_DEVICE_SPECS
      value: "true"
    - name: FAIL_ON_INIT_ERROR
      value: "true"
    - name: DEVICE_LIST_STRATEGY
      value: envvar
    - name: DEVICE_ID_STRATEGY
      value: uuid
    - name: NVIDIA_VISIBLE_DEVICES
      value: all
    - name: NVIDIA_DRIVER_CAPABILITIES
      value: all
    - name: NODE_LABEL
      value: nvidia.com/device-plugin.config
  config:
    name: device-plugin-config
    default: default
migManager:
  enabled: true
  repository: nvcr.io/nvidia/cloud-native
  image: k8s-mig-manager
  version: v0.12.1-ubuntu20.04
  imagePullPolicy: IfNotPresent
  env:
    - name: WITH_REBOOT
      value: "false"
  config:
    default: all-disabled
    name: custom-mig-parted-config
  gpuClientsConfig:
    name: ""
  • 測試用的device-plugin配置文件。
---
# Source: gpu-operator/templates/plugin_config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: device-plugin-config
  namespace: gpu-operator
  labels:
    app.kubernetes.io/name: gpu-operator
    helm.sh/chart: gpu-operator-v24.3.0
    app.kubernetes.io/instance: stable
    app.kubernetes.io/version: "v24.3.0"
    app.kubernetes.io/managed-by: Helm
data:
  default: |-
    version: v1
    flags:
      migStrategy: none
  mig-mixed: |-
    version: v1
    flags:
      migStrategy: mixed
  mig-single: |-
    version: v1
    flags:
      migStrategy: single
  config1: |-
    flags:
      migStrategy: none
    sharing:
      mps:
        renameByDefault: true
        resources:
        - devices:
          - "0"
          - "1"
          name: nvidia.com/gpu
          replicas: 2
    version: v1

測試用的mig策略配置文件

apiVersion: v1
kind: ConfigMap
metadata:
  name: custom-mig-parted-config
  namespace: gpu-operator
data:
  config.yaml: |
    version: v1
    # 針對第一個卡開啟的MIG
    mig-configs:
      custom-1:
        - devices: [0]
          mig-enabled: true
          mig-devices:
            "1g.10gb": 2
            "2g.20gb": 1
            "3g.40gb": 1

      all-disabled:
        - devices: all
          mig-enabled: false

      all-enabled:
        - devices: all
          mig-enabled: true
          mig-devices: {}

      # A100-40GB, A800-40GB
      all-1g.5gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "1g.5gb": 7

      all-1g.5gb.me:
        - devices: all
          mig-enabled: true
          mig-devices:
            "1g.5gb+me": 1

      all-2g.10gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "2g.10gb": 3

      all-3g.20gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "3g.20gb": 2

      all-4g.20gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "4g.20gb": 1

      all-7g.40gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "7g.40gb": 1

      # H100-80GB, H800-80GB, A100-80GB, A800-80GB, A100-40GB, A800-40GB
      all-1g.10gb:
        # H100-80GB, H800-80GB, A100-80GB, A800-80GB
        - device-filter: ["0x233010DE", "0x233110DE", "0x232210DE", "0x20B210DE", "0x20B510DE", "0x20F310DE", "0x20F510DE"]
          devices: all
          mig-enabled: true
          mig-devices:
            "1g.10gb": 7

        # A100-40GB, A800-40GB
        - device-filter: ["0x20B010DE", "0x20B110DE", "0x20F110DE", "0x20F610DE"]
          devices: all
          mig-enabled: true
          mig-devices:
            "1g.10gb": 4

      # H100-80GB, H800-80GB, A100-80GB, A800-80GB
      all-1g.10gb.me:
        - devices: all
          mig-enabled: true
          mig-devices:
            "1g.10gb+me": 1

      # H100-80GB, H800-80GB, A100-80GB, A800-80GB
      all-1g.20gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "1g.20gb": 4

      all-2g.20gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "2g.20gb": 3

      all-3g.40gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "3g.40gb": 2

      all-4g.40gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "4g.40gb": 1

      all-7g.80gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "7g.80gb": 1

      # A30-24GB
      all-1g.6gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "1g.6gb": 4

      all-1g.6gb.me:
        - devices: all
          mig-enabled: true
          mig-devices:
            "1g.6gb+me": 1

      all-2g.12gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "2g.12gb": 2

      all-2g.12gb.me:
        - devices: all
          mig-enabled: true
          mig-devices:
            "2g.12gb+me": 1

      all-4g.24gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "4g.24gb": 1

      # H100 NVL, H800 NVL, GH200
      all-1g.12gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "1g.12gb": 7

      all-1g.12gb.me:
        - devices: all
          mig-enabled: true
          mig-devices:
            "1g.12gb+me": 1

      all-1g.24gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "1g.24gb": 4

      all-2g.24gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "2g.24gb": 3

      # H100 NVL, H800 NVL
      all-3g.47gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "3g.47gb": 2

      all-4g.47gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "4g.47gb": 1

      all-7g.94gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "7g.94gb": 1

      # H100-96GB, PG506-96GB, GH200
      all-3g.48gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "3g.48gb": 2

      all-4g.48gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "4g.48gb": 1

      all-7g.96gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "7g.96gb": 1


      # H100-96GB, GH200, H100 NVL, H800 NVL, H100-80GB, H800-80GB, A800-40GB, A800-80GB, A100-40GB, A100-80GB, A30-24GB, PG506-96GB
      all-balanced:
        # H100 NVL, H800 NVL
        - device-filter: ["0x232110DE", "0x233A10DE"]
          devices: all
          mig-enabled: true
          mig-devices:
            "1g.12gb": 1
            "2g.24gb": 1
            "3g.47gb": 1

        # H100-80GB, H800-80GB, A100-80GB, A800-80GB
        - device-filter: ["0x233010DE", "0x233110DE", "0x232210DE", "0x20B210DE", "0x20B510DE", "0x20F310DE", "0x20F510DE"]
          devices: all
          mig-enabled: true
          mig-devices:
            "1g.10gb": 2
            "2g.20gb": 1
            "3g.40gb": 1

        # A100-40GB, A800-40GB
        - device-filter: ["0x20B010DE", "0x20B110DE", "0x20F110DE", "0x20F610DE"]
          devices: all
          mig-enabled: true
          mig-devices:
            "1g.5gb": 2
            "2g.10gb": 1
            "3g.20gb": 1

        # A30-24GB
        - device-filter: "0x20B710DE"
          devices: all
          mig-enabled: true
          mig-devices:
            "1g.6gb": 2
            "2g.12gb": 1

        # H100-96GB, PG506-96GB, GH200
        - device-filter: ["0x234210DE", "0x233D10DE", "0x20B610DE"]
          devices: all
          mig-enabled: true
          mig-devices:
            "1g.12gb": 2
            "2g.24gb": 1
            "3g.48gb": 1
  • 部署完成之后查看服務狀態
kubectl get pod -n gpu-operator
  • 使用打對gpu節點打標簽的方式開啟對應的share策略

操作方法:

  • 開啟MPS策略:將節點標簽 nvidia.com/device-plugin.config 的值修改成具體的MPS策略,具體策略值必須存在配置的ConfigMap中,例如上面配置中的 config1,它表示針對兩個卡開啟的MPS。
  • 開啟MIG策略:將節點標簽 nvidia.com/device-plugin.config 的值修改成mig-mixed策略,它表示可以允許不同規格的MIG出現在一臺機器上。然后還需要將節點標簽 nvidia.com/mig.config 的值修改成具體的mig策略配置名字。例如上面的 custom-1,它表示針對第一個卡開啟的MIG策略。
  • 開啟之后的驗證方式參考實踐與測試


責任編輯:武曉燕 來源: 運維開發故事
相關推薦

2013-04-02 09:15:40

服務器虛擬化

2013-01-04 10:44:31

IBMdW

2011-04-12 09:07:47

磁盤空間利用率虛擬化的隱藏成本

2012-11-07 15:07:30

VMware虛擬化

2012-05-08 13:24:45

負載均衡帶寬銳捷網絡

2022-08-12 11:37:16

優化實踐

2015-10-15 09:09:38

Oracle數據庫華為

2013-08-21 14:20:50

飛魚星流控王飛魚星

2009-05-26 17:34:14

VMware虛擬化服務器

2013-09-03 18:07:49

GPU虛擬化華為NVIDIA

2013-11-15 09:51:21

云端渲染NVIDIA

2011-07-13 09:16:08

服務器虛擬化數據中心

2018-07-11 15:21:25

GPU虛擬化技術

2020-06-23 07:56:57

虛擬桌面AMDNvidia

2015-06-04 13:44:34

5G

2024-08-09 15:50:15

2023-04-04 09:22:50

LinuxCPU命令

2017-08-25 15:56:54

Linuxproc文件系統CPU利用率

2019-04-16 16:23:29

GPU虛擬化CPU

2011-03-17 13:54:42

查詢參數SQL語句利用率
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品一区二区三区四区 | av首页在线| 国产精品揄拍一区二区 | 日本成人在线网址 | 国产欧美一级二级三级在线视频 | 欧美日本韩国一区二区 | 久久高清精品 | 欧美精品网| 女同av亚洲女人天堂 | 欧美日韩在线免费观看 | 国产精品久久9 | 91新视频| 欧美一级一 | 欧美aaa级| 不卡在线视频 | 亚洲成人自拍网 | 色呦呦在线 | 久久99精品久久久久久 | 欧美一区成人 | 欧美乱淫视频 | 精彩视频一区二区三区 | 日韩欧美一级精品久久 | 欧美aaaa视频| 最近日韩中文字幕 | 成人国产精品免费观看 | 久久99精品久久久久久琪琪 | 麻豆成人在线视频 | 亚洲国产欧美在线人成 | 91成人免费看片 | 国产伦一区二区三区视频 | 欧美久久久久久 | 亚洲国产专区 | 99热精品久久 | 日本啊v在线 | 日韩精品一区二区三区第95 | 91porn在线| 日韩欧美视频网站 | 国产日产久久高清欧美一区 | 视频在线一区二区 | 狠狠操网站| 免费一级黄色录像 |