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

前言

为什么需要 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 切分

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL】 表的增删操作

目录 1.Create(增) 1.1.单行数据 全列插入 1.2.多行数据 指定列插入 1.3.插入否则更新 1.4.替换数据(REPLACE) 2.Delete(删) 2.1.删除表中的某个条目 2.2.删除整张表数据 2.3.截断表 1.Create…

智汇云舟亮相WAFI世界农业科技创新大会,并参编数字农业产业图谱

10月10日,2024WAFI世界农业科技创新大会农食行业创新与投资峰会在北京金海湖国际会展中心举行。中国农业大学MBA教育中心主任、教授付文阁、平谷区委常委、统战部部长刘堃、华为公共事业军团数字政府首席专家刘丹、荷兰瓦赫宁根大学前校长Aalt Dijkhuizen、牧原食品…

【论文阅读】Bi-Mamba+: Bidirectional Mamba for Time Series Forecasting

文章目录 概要阅读背景知识引言创新之处 研究方法概述方法部分的核心模块多尺度打补丁(Multi-Scale Patching)Mamba:全局模式专家Local Window Transformer(LWT):局部变化专家长短期路由器(Long…

pikachu靶场SQL-Inject中的“delete“注入、“http header“注入、盲注、宽字节注入

"delete"注入 抓包发现在留言时有messagehhhh&submitsubmit两个参数,但并未涉及到数据库操作。除此之外,在删除留言时URL中拼接了?id的参数 构造?id59有报错回显 利用报错注入函数来查询数据,有空格编译不通过&#xff0c…

Agent智能体?我们要的到底是什么

What is an agent? ❝ 近年来,大型语言模型(LLM)的能力越来越强,应用范围也越来越广泛,其中一个热门方向就是智能体(Agent)。但在这一切的背后,我们真正追求的是什么?是…

SSM框架学习(七、MyBatis-Plus高级用法:最优化持久层开发)

目录 一、MyBatis-Plus快速入门 1.简介 2.快速入门 二、MyBatis-Plus核心功能 1.基于Mapper接口CRUD (1)Insert 方法 (2)Delete方法 (3)Update 方法 (4)Select方法 2.基于Serv…

解决在Windows中安装tensorflow2.10无法检测到GPU的问题

解决在Windows中安装tensorflow2.10无法检测到GPU的问题 官方给出的Windows本地安装方式 更新显卡驱动到最新。安装anaconda或miniconda作为python环境的管理工具。创建新的环境tf:conda create --name tf python3.9,然后进入改环境:conda …

【学习笔记】理解 C++ 中 reinterpret_cast 和 C 风格类型转换的区别

【学习笔记】理解 C 中 reinterpret_cast 和 C 风格类型转换的区别 在 C 中,类型转换是一个常见的操作,特别是当我们需要在不同类型之间进行数据操作时。本篇笔记将通过两个具体的例子来讨论 reinterpret_cast 和 C 风格的类型转换的区别。 示例 1&…

【uniapp】设置公共样式,实现公共背景等

目录 1、 全局渐变背景色 2.1 创建common目录 2.2 在common下新建style和images等目录 2.3 在style下新建common-style.scss 2.4 common-style输入全局渐变颜色 2.5 引入样式 2.6 业务页面引入 2.7 展示 2、全局字体颜色 2.1 新建base-style.scss文件 2.2 设置base-…

【动手学深度学习】7.6. 残差网络(ResNet)(个人向笔记)

1. ResNet精读论文视频的Introduction部分 深度卷积神经网络好,好在可以叠加很多层,每一层都可以提取不一样的特征但是网络特别深的时候,梯度要么爆炸要么消失,我们能做的就是将参数随机初始化做好,或者是在中间加一些…

ai聊天对话页面-uniapp

流式传输打字机效果,只支持uniapp内使用 ,下载地址 https://download.csdn.net/download/qq_54123885/89899859

Java基于SpringBoot微信小程序的跳蚤市场系统设计与实现(lw+数据库+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

WT2003H语音芯片MCU下载方案助力电动车智能化升级:实现多功能语音提示+报警功能

一:产品市场 随着科技的发展,电瓶车在技术革新上也在不断进步,如今许多厂家,都会加入语音提示功能,能在倒车、喇叭、故障时发出语音报警,提示骑行者电量不足、倒车请注意、故障语音提示等;唯创…

微信小程序引入组件教程

1、安装 node.js 下载网址:https://nodejs.org 2.通过 npm 安装 npm init -y npm i vant/weapp -S --production 3、修改 app.json 将 app.json 中的 “style”: “v2” 去除 4、修改 project.config.json 关于修改 project.config.json 的详细内容&#x…

Linux系统重建Grub引导的方法

一、问题出现的原因 在安装双系统时,我们都是先安装Windows系统,再安装Linux系统,这样在启动计算机时,两个系统都可以被引导启动,并在开机界面可以进行选择。这是因为Linux使用的操作系统引导加载器Grub可以引导如Win…

Qt- QSS风格选择器常用属性选择器样式表盒子

1. 风格设置 Qt 提供了 3 种整体风格,使用 QStyleFactory::keys() 来获取 (windowsvista 、Windows 、Fusion) 可以在 main.cpp 中调用 setStyle 方法对应用程序进行全局风格的设置 int main(int argc, char *argv[]) {QApplication a(arg…

Unity中使用Json导入项目无法识别Newtonsoft.Json

Unity导入项目无法识别Newtonsoft.Json 因为项目中用到了JSON解析,所以引入了一个解析类库 using Newtonsoft.Json.Linq; 换了台设备之后,导入这个项目之后,这个引用就标红了,找不到类库。 因为是C#报错所以研究了半天visual stu…

自动驾驶系列—深入解析自动驾驶系统验车平台:确保车辆交付质量的关键工具

🌟🌟 欢迎来到我的技术小筑,一个专为技术探索者打造的交流空间。在这里,我们不仅分享代码的智慧,还探讨技术的深度与广度。无论您是资深开发者还是技术新手,这里都有一片属于您的天空。让我们在知识的海洋中…

LeetCode刷题日记之贪心算法(二)

目录 前言买卖股票的最佳时机II跳跃游戏跳跃游戏II总结 前言 在上一篇贪心算法的学习中,我们探讨了贪心算法的基本思路和逻辑框架。在这篇文章中,我将继续分享几道经典的LeetCode贪心算法题,并探讨其背后的解题思路和技巧。希望通过这些题目…

Java入门-创建对象

Java包管理器 包(package)的导入 Java体系非常庞大,为了管理更多的代码互不侵犯,采用了一个叫“包管理”的机制来管理代码,简单来说就是把不同的Java代码放在不同的文件夹里,这个文件夹就是“包”。对于使…