开源vGPU方案 HAMi实现细粒度GPU切分——筑梦之路

news2024/11/27 12:33:24

前言

为什么需要 GPU 共享、切分等方案?

在使用GPU的过程中我们会发现,直接在裸机环境使用,都可以多个进程共享 GPU,怎么到 k8s 环境就不行了?

1. 资源感知

在 k8s 中资源是和节点绑定的,对于 GPU 资源,我们使用 NVIDIA 提供的 device-plugin 进行感知,并上报到 kube-apiserver,这样我们就能在 Node 对象上看到对应的资源。

kubectl describe node gpu01|grep Capacity -A 7
Capacity:
  cpu:                128
  ephemeral-storage:  879000896Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             1056457696Ki
  nvidia.com/gpu:     8
  pods:               110

该节点除了基础的 cpu、memory 之外,还有一个nvidia.com/gpu: 8 信息,表示该节点上有 8 个 GPU 。

2. 资源申请

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  containers:
  - name: gpu-container
    image: nvidia/cuda:11.0-base   # 一个支持 GPU 的镜像
    resources:
      limits:
        nvidia.com/gpu: 1          # 申请 1 个 GPU
    command: ["nvidia-smi"]         # 示例命令,显示 GPU 的信息
  restartPolicy: OnFailure

kube-scheduler 在调度该 Pod 时就会将其调度到一个拥有足够 GPU 资源的 Node 上。同时该 Pod 申请的部分资源也会标记为已使用,不会再分配给其他 Pod。

总结一下:

1)device-plugin 感知到节点上的物理 GPU 数量,上报到 kube-apiserver

2)kube-scheduler 调度 Pod 时会根据 pod 中的 Request 消耗对应资源

即:Node 上的 GPU 资源被 Pod 申请之后,在 k8s 中就被标记为已消耗了,后续创建的 Pod 会因为资源不够导致无法调度。

实际上:可能 GPU 性能比较好,可以支持多个 Pod 共同使用,但是 k8s 中的调度限制导致多个 Pod 无法正常共享。因此,我们才需要 GPU 共享、切分等方案。

什么是 HAMi?

https://github.com/Project-HAMi/HAMi

HAMi 全称是:Heterogeneous AI Computing Virtualization Middleware,HAMi 给自己的定位或者希望是做一个异构算力虚拟化平台。原第四范式 k8s-vgpu-scheduler, 这次改名 HAMi 同时也将核心的 vCUDA 库 libvgpu.so 也开源了。但是现在比较完善的是对 NVIDIA GPU 的 vGPU 方案,因此我们可以简单认为他就是一个 vGPU 方案。

整体架构

特性

使用 HAMi 最大的一个功能点就是可以实现 GPU 的细粒度的隔离,可以对 core 和 memory 使用 1% 级别的隔离。

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  containers:
    - name: ubuntu-container
      image: ubuntu:18.04
      command: ["bash", "-c", "sleep 86400"]
      resources:
        limits:
          nvidia.com/gpu: 1 # 请求1个vGPUs
          nvidia.com/gpumem: 3000 # 每个vGPU申请3000m显存 (可选,整数类型)
          nvidia.com/gpucores: 30 # 每个vGPU的算力为30%实际显卡的算力 (可选,整数类型)

----------------------
nvidia.com/gpu:请求一个 GPU
nvidia.com/gpumem:只申请使用 3000M GPU Memory
nvidia.com/gpucores:申请使用 30% 的 GPU core,也就是该 Pod 只能使用到 30% 的算力

设计

HAMi 实现 GPU core 和 memory 隔离、限制是使用的 vCUDA 方案

 HAMi 使用的是软件层面的 vCUDA 方案,对 NVIDIA 原生的 CUDA 驱动进行重写(libvgpu.so),然后挂载到 Pod 中进行替换,然后在自己的实现的 CUDA 驱动中对 API 进行拦截,实现资源隔离以及限制的效果。

例如:原生 libvgpu.so 在进行内存分配时,只有在 GPU 内存真的用完的时候才会提示 CUDA OOM,但是对于 HAMi 实现的 libvgpu.so 来说,检测到 Pod 中使用的内存超过了 Resource 中的申请量就直接返回 OOM,从而实现资源的一个限制。

然后在执行 nvidia-smi 命令查看 GPU 信息时,也只返回 Pod Resource 中申请的资源,这样在查看时也进行隔离。

HAMi 部署

HAMi 提供了 Helm Chart 安装

1. 部署 GPU Operator

HAMi 会依赖 NVIDIA 的那一套,因此推荐先部署 GPU-Operator

此处留着补充

部署好 GPU Operator 之后再部署 HAMi。

2. 部署 HAMi

# 添加repo仓库

helm repo add hami-charts https://project-hami.github.io/HAMi/

# 获取k8s版本

kubectl version

# 在安装过程中须根据集群服务端版本(上一条指令的结果)指定调度器镜像版本,例如集群服务端版本为 v1.27.4,则可以使用如下指令进行安装

helm install hami hami-charts/hami --set scheduler.kubeScheduler.imageTag=v1.27.4 -n kube-system

# 通过 kubectl get pods 指令看到 vgpu-device-plugin 与 vgpu-scheduler 两个 pod 状态为Running 即为安装成功

kubectl get pods -n kube-system|grep hami
hami-device-plugin-b6mvj                          2/2     Running   0          42s
hami-scheduler-7f5c5ff968-26kjc                   2/2     Running   0          42s

 3. 自定义配置

官方文档:

HAMi-config-cn.md: https://github.com/Project-HAMi/HAMi/blob/master/docs/config_cn.md

在安装过程中,通过-set来修改以下的客制化参数,例如

helm install vgpu vgpu-charts/vgpu --set devicePlugin.deviceMemoryScaling=5 ...
  • devicePlugin.deviceSplitCount:整数类型,预设值是 10。GPU 的分割数,每一张 GPU 都不能分配超过其配置数目的任务。若其配置为 N 的话,每个 GPU 上最多可以同时存在 N 个任务。

  • devicePlugin.deviceMemoryScaling: 浮点数类型,预设值是 1。NVIDIA 装置显存使用比例,可以大于 1(启用虚拟显存,实验功能)。对于有 M 显存大小的 NVIDIA GPU,如果我们配置devicePlugin.deviceMemoryScaling参数为 S ,在部署了我们装置插件的 Kubenetes 集群中,这张 GPU 分出的 vGPU 将总共包含 S * M 显存。

  • devicePlugin.migStrategy: 字符串类型,目前支持"none“与“mixed“两种工作方式,前者忽略 MIG 设备,后者使用专门的资源名称指定 MIG 设备,使用详情请参考 mix_example.yaml,默认为"none"

  • devicePlugin.disablecorelimit: 字符串类型,"true"为关闭算力限制,"false"为启动算力限制,默认为"false"

  • scheduler.defaultMem: 整数类型,预设值为 5000,表示不配置显存时使用的默认显存大小,单位为 MB

  • scheduler.defaultCores: 整数类型(0-100),默认为 0,表示默认为每个任务预留的百分比算力。若设置为 0,则代表任务可能会被分配到任一满足显存需求的 GPU 中,若设置为 100,代表该任务独享整张显卡

  • scheduler.defaultGPUNum: 整数类型,默认为 1,如果配置为 0,则配置不会生效。当用户在 pod 资源中没有设置 nvidia.com/gpu 这个 key 时,webhook 会检查 nvidia.com/gpumem、resource-mem-percentage、nvidia.com/gpucores 这三个 key 中的任何一个 key 有值,webhook 都会添加 nvidia.com/gpu 键和此默认值到 resources limit 中。

  • resourceName: 字符串类型, 申请 vgpu 个数的资源名, 默认: "nvidia.com/gpu"

  • resourceMem: 字符串类型, 申请 vgpu 显存大小资源名, 默认: "nvidia.com/gpumem"

  • resourceMemPercentage: 字符串类型,申请 vgpu 显存比例资源名,默认: "nvidia.com/gpumem-percentage"

  • resourceCores: 字符串类型, 申请 vgpu 算力资源名, 默认: "nvidia.com/cores"

  • resourcePriority: 字符串类型,表示申请任务的任务优先级,默认: "nvidia.com/priority"

除此之外,容器中也有对应配置

  • GPU_CORE_UTILIZATION_POLICY: 字符串类型,"default", "force", "disable" 代表容器算力限制策略, "default"为默认,"force"为强制限制算力,一般用于测试算力限制的功能,"disable"为忽略算力限制

  • ACTIVE_OOM_KILLER: 字符串类型,"true", "false" 代表容器是否会因为超用显存而被终止执行,"true"为会,"false"为不会

4. 验证

查看 Node GPU 资源

环境中只有一个物理 GPU,但是 HAMi 默认会扩容 10 倍,理论上现在 Node 上能查看到 1*10 = 10 个 GPU。

默认参数就是切分为 10 个,可以设置

kubectl get node xxx -oyaml|grep capacity -A 7
  capacity:
    cpu: "4"
    ephemeral-storage: 206043828Ki
    hugepages-1Gi: "0"
    hugepages-2Mi: "0"
    memory: 15349120Ki
    nvidia.com/gpu: "10"
    pods: "110"

 验证显存和算力限制

使用以下 yaml 来创建 Pod,注意 resources.limit 除了原有的 nvidia.com/gpu 之外还新增了 nvidia.com/gpumem 和 nvidia.com/gpucores,用来指定显存大小和算力大小。

  • nvidia.com/gpu:请求的 vgpu 数量,例如 1

  • nvidia.com/gpumem :请求的显存数量,例如 3000M

  • nvidia.com/gpumem-percentage:显存百分百,例如 50 则是请求 50%显存

  • nvidia.com/priority: 优先级,0 为高,1 为低,默认为 1。

    • 对于高优先级任务,如果它们与其他高优先级任务共享 GPU 节点,则其资源利用率不会受到 resourceCores 的限制。换句话说,如果只有高优先级任务占用 GPU 节点,那么它们可以利用节点上所有可用的资源。

    • 对于低优先级任务,如果它们是唯一占用 GPU 的任务,则其资源利用率也不会受到 resourceCores 的限制。这意味着如果没有其他任务与低优先级任务共享 GPU,那么它们可以利用节点上所有可用的资源。

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  containers:
    - name: ubuntu-container
      image: ubuntu:18.04
      command: ["bash", "-c", "sleep 86400"]
      resources:
        limits:
          nvidia.com/gpu: 1 # 请求1个vGPUs
          nvidia.com/gpumem: 3000 # 每个vGPU申请3000m显存 (可选,整数类型)
          nvidia.com/gpucores: 30 # 每个vGPU的算力为30%实际显卡的算力 (可选,整数类型)
kubectl exec -it gpu-pod -- bash
root@gpu-pod:/# nvidia-smi
[HAMI-core Msg(16:139711087368000:libvgpu.c:836)]: Initializing.....
Mon Apr 29 06:22:16 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.54.14              Driver Version: 550.54.14      CUDA Version: 12.4     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  Tesla T4                       On  |   00000000:00:07.0 Off |                    0 |
| N/A   33C    P8             15W /   70W |       0MiB /   3000MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+
[HAMI-core Msg(16:139711087368000:multiprocess_memory_limit.c:434)]: Calling exit handler 16

最后的日志就是 HAMi 的 CUDA 驱动打印

[HAMI-core Msg(16:139711087368000:multiprocess_memory_limit.c:434)]: Calling exit handler 16

HAMi 大致实现原理

通过替换容器中的 libvgpu.so 库,实现 CUDA API 拦截,最终实现对 GPU core 和 memory 的隔离和限制。

参考资料: 

第四范式 k8s-vgpu-scheduler: https://github.com/4paradigm/k8s-vgpu-scheduler

本文搜集来自开源 vGPU 方案:HAMi,实现细粒度 GPU 切分

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2220671.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】僵尸进程和孤儿进程

一、僵尸进程 何为僵尸进程? 在 Unix/Linux 系统中,正常情况下,子进程是通过父进程创建的,且两者的运行是相互独立的,父进程永远无法预测子进程到底什么时候结束。当一个进程调用 exit 命令结束自己的生命时&#xff…

《编程入门与提高:开启数字世界的大门》

《编程入门与提高:开启数字世界的大门》 一、引言二、编程入门的基础知识(一)编程语言的选择(二)编程环境的搭建(三)编程的基本概念(四)编程的基本语法 三、编程入门的方…

哪些方法可以缓解面试紧张?

面试紧张是许多人在面对重要职业机会时的一种常见情绪。虽然一定程度的紧张可能激发人的潜能,但过度的紧张则可能影响到面试表现。为了缓解面试紧张,以下是一些有效的方法: 1.充分准备: 深入了解公司背景、职位要求以及公司文化…

地方门户分类信息网站源码系统 用户可以自由发帖 PHP+MySQL组合开发 带完整的安装代码包以及搭建部署教程

系统概述 地方门户分类信息网站源码系统是一个基于PHP和MySQL开发的强大平台,旨在帮助用户轻松搭建地方性的分类信息网站。该系统集成了众多实用功能,支持用户自由发帖、浏览和搜索各类信息,如二手交易、求职招聘、房屋租售、生活服务、商家…

Python网络请求库requests的10个基本用法

大家好!今天我们要聊聊Python中非常实用的一个库——requests。这个库让发送HTTP请求变得超级简单。无论你是想抓取网页数据还是测试API接口,requests都能派上大用场。下面我们就一起来看看如何使用requests完成一些常见的任务。 引言 随着互联网技术的…

空洞卷积:Atrous/Dilated convolution - 语义分割中多用到

没办法,我还是很多基础的、底层的模块不通透,读论文难免会受到阻碍,而且这现在科研任务很急了,必须要马上动手实验,全给我弄明白、特别是算法! 空洞卷积-可变形卷积-这一个个我都要。 空洞卷积据说在语义分…

推动AI技术研发与应用,景联文科技提供专业高效图像采集服务

景联文科技提供专业图像采集服务,涵盖多个领域的应用需求。 包含人体图像、人脸图像、手指指纹、手势识别、交通道路、车辆监控等图像数据集,计算机视觉图像数据集超400TB,支持免费试采试标。 高质量人像采集服务:支持不同光线条件…

Netty入门基础:Netty架构设计模型介绍(主从Reactor多线程模型,Futrue-Listener模型)

文章目录 🎵单Reactor单线程✏单Reactor多线程🛒主从Reactor多线程🎐Netty模型🚴‍♀️Future-listener模型 🎵单Reactor单线程 Reactor通过select监控客户端的事件,通过dispatch分发。 如果是建立连接事件…

Unity-RetargetPro3-动画插件试用

一个名气大于实战的插件 目录 初见这个插件, 打开文档看看 下载并打开Demo项目 直接看Editor代码吧 这个插件,可以放弃了 初见这个插件, 觉得,1.都已经是3.0版本,不错哦 看上去,2.目录也 不错,有分Core,plugin等 (应该感觉,怎么也是大公司的代码分拆出来吧,感…

计算机的错误计算(一百三十)

摘要 用手持式计算器计算 则输出为0 . 计算机的错误计算(四十)探讨了计算器的计算精度问题。为了回应一位计算器收藏家来信中的疑问,既(四十)后再续若干节,以便更为广泛地讨论计算器的上述问题。 例1. …

【思维导图】C语言—数据类型和变量

今天我们来回顾——C语言【数据类型和变量】 我们先梳理一下思路:首先学习数据的类型,然后学会用类型去创建变量,接着学习操作符进行变量之间的运算,最后学习 scanf 输入数据, printf 进行数据的打印。回顾的时候最好…

【K8S系列】Kubernetes Pod 状态详细介绍及异常状态解决方案

在 Kubernetes 中,Pod 是最小的可调度单元,负责运行一个或多个容器。Pod 的状态能够反映其生命周期中的不同阶段,帮助用户了解当前的运行状况。本文将详细介绍 Kubernetes Pod 的各种状态及其可能的异常状态解决方案。 一、Pod 状态概览 Po…

【Git】远程操作-标签管理-多人协作

远程操作 分布式版本控制系统 概念理解 Git就像正在看的一本书。每当看完一章,可以将其保存起来,如果后面想修改或者查看以前自己看到哪里,随时可以翻看。Git就是帮助记录这些修改的工具,主要负责记录每次改动,就类似…

git命令笔记(速查速查)

git命令功能总结 1.创建git的本地仓库2. 配置本地仓库(name和email地址)3. 工作区、版本库、暂存区、对象区3.1 add, commit3.2 打印提交日志3.2 修改文件 4.版本回退(git reset)5. 撤销修改(在push之前撤销)6.删除版本库中的文件…

Github + 自定义域名搭建个人静态站点

Github 自定义域名搭建个人静态站点 使用 Github 部署一个自己的免费站点给你的站点添加上自定义域名 本文基于腾讯云基于二级域名, 作用于 Github 实现自定义域名站点 使用 Github 部署一个自己的免费站点 首先你得有一个 Github 账号, 没有就去注册一个,网上有教程,本文跳…

字典学习算法

分为固定基字典和学习型字典 学习型字典 是指通过训练大量与目标数据相似的数据,学习其特征获得的字典。字典学习主要包括两个阶段,一个是字典构建阶段,一个是利用字典进行样本表示阶段。 首次提出:最优方向法(Method …

JSON 注入攻击 API

文章目录 JSON 注入攻击 API"注入所有东西"是"聪明的"发生了什么? 什么是 JSON 注入?为什么解析器是问题所在解析不一致 JSON 解析器互操作性中的安全问题处理重复密钥的方式不一致按键碰撞响应不一致JSON 序列化(反序列化)中的不一致 好的。JSON 解析器…

Vue--数据代理

Object.defineProperty const person {}; // 创建一个新对象 person.name‘xusx’ // 通过 defineProperty 使用数据描述符添加对象属性的示例 Object.defineProperty(person, “age”, { value: 37, // 默认值 writable: true, // 不可写 默认false enumerable: true, // 是…

【数据库系统概论】第3章 关系数据库标准语言SQL(一)数据定义(超详细)

教材: 数据库系统概论(第6版)王珊,杜小勇,陈红编著 目录 一、SQL概述 1.1 SQL 的产生与发展 1.2 SQL的特点 1.3 SQL的基本概念 二、数据定义 2.1 数据库的定义 2.2 数据表的定义 2.3 模式的定义 一、SQL概述 1974年IBM为关系DBMS设…

3.cpp基本数据类型

cpp基本数据类型 1.cpp基本数据类型 1.cpp基本数据类型 C基本数据类型和C语言的基本数据类型差不多 注意bool类型&#xff1a;存储真值 true 或假值 false&#xff0c;C语言编译器C99以上支持。 C语言的bool类型&#xff1a;要添加 #include <stdbool.h>头文件 #includ…