GPU虚拟化实现(一)
目前GPU虚拟化的主流方案
PCIe直通模式
PCIe直通模式(PCIe Passthrough)是一种虚拟化技术,允许虚拟机(VM)直接访问物理硬件设备(如显卡、网卡、存储控制器等),绕过虚拟化层(Hypervisor)的主机操作系统。这种技术使得虚拟机可以像物理机一样直接与硬件交互,从而显著提高性能。通过直通模式,虚拟机可以直接使用设备的原生驱动程序,而无需依赖主机的模拟层。
PCIe直通模式的优点
- 高性能:
- 直通模式消除了虚拟化层的性能开销,虚拟机可以接近物理机的原生性能。例如,直通显卡(GPU Passthrough)可以让虚拟机运行3D游戏或高性能计算任务。
- 对于网络设备(如网卡),直通可以大幅降低延迟并提高吞吐量。
- 原生硬件支持:
- 虚拟机可以使用设备的完整功能,而不仅仅是虚拟化层模拟的部分功能。例如,某些专业显卡的高级功能可能无法通过模拟实现,但直通可以完全支持。
- 隔离性:
- 直通设备完全由虚拟机控制,主机和其他虚拟机无法访问该设备,从而提高了设备隔离和安全性。
PCIe直通模式的缺点
- 硬件资源独占:
- 直通设备只能被一个虚拟机独占,无法在多个虚拟机之间共享。例如,如果一个显卡被直通给虚拟机A,其他虚拟机或主机无法使用该显卡。
- 配置复杂:
- 设置PCIe直通需要特定的硬件支持(如IOMMU)和软件配置(如修改虚拟机配置文件、绑定设备驱动)。此外,不同硬件和Hypervisor的兼容性问题可能导致配置失败。
- 需要手动处理设备的分组(IOMMU Group),确保同一分组内的设备不会冲突。
- 硬件兼容性问题:
- 并非所有硬件都支持直通。例如,某些设备的驱动可能无法在直通模式下正常工作,或者设备的固件不支持IOMMU。
- 某些主板或BIOS可能需要额外的设置(如启用VT-d或调整PCIe插槽配置)。
- 主机资源限制:
- 直通会占用主机的PCIe设备,主机本身无法使用这些设备,可能影响主机的功能(如直通显卡后主机可能无法显示输出)。
SR-IOV技术
SR-IOV(Single Root I/O Virtualization)是一种硬件虚拟化技术,旨在提高虚拟化环境中I/O设备的性能和效率。它允许一个物理设备(通常是网卡或存储控制器)被划分为多个虚拟功能(Virtual Functions, VF),每个虚拟功能可以直接分配给不同的虚拟机(VM),从而实现高效的资源共享和接近原生硬件的性能。
SR-IOV技术的优点
- 高性能:
- SR-IOV提供了接近原生硬件的性能,因为虚拟机直接与硬件的虚拟功能交互,减少了虚拟化层的开销(如软件模拟或数据拷贝)。
- 对于网络设备,SR-IOV可以显著降低延迟并提高吞吐量,接近物理网卡的性能。
- 资源共享:
- 与PCIe直通模式(Passthrough)不同,SR-IOV允许多个虚拟机共享同一个物理设备。通过将一个设备划分为多个VF,每个虚拟机可以分配到一个独立的VF,实现资源的有效利用。
- 可扩展性:
- 一个物理设备可以支持多个VF(具体数量取决于硬件),因此可以支持多个虚拟机同时运行,适合大规模虚拟化环境。
- 隔离性:
- 每个VF是独立的,虚拟机之间的数据通过硬件隔离,避免了软件层面的干扰或安全风险。
SR-IOV技术的缺点
- 硬件依赖:
- SR-IOV需要硬件支持,只有特定的设备(如某些高端网卡或存储控制器)支持SR-IOV功能。常见的消费级硬件可能不支持此技术。
- 同时需要主板和CPU支持IOMMU(VT-d或AMD-Vi),否则无法实现内存隔离。
- 配置复杂性:
- 虽然比PCIe直通模式稍简单,但SR-IOV的配置仍然需要一定的技术知识。例如,需要在主机上启用SR-IOV支持、配置VF数量,以及将VF分配给虚拟机。
- 不同厂商的设备可能有不同的配置方式和兼容性问题。
- 功能限制:
- VF的功能通常是PF的一个子集,某些高级功能或管理功能可能只能通过PF访问,虚拟机无法完全利用设备的全部特性。
- 例如,某些网卡的VF可能不支持某些高级网络功能(如特定类型的卸载功能)。
- 资源分配不灵活:
- VF的数量和性能由硬件决定,无法动态调整。如果VF数量不足以满足虚拟机需求,可能需要额外购买支持更多VF的硬件。
- 不支持所有设备类型:
- SR-IOV主要用于网卡和存储设备,GPU等其他类型的设备很少支持SR-IOV(尽管有一些新兴技术如NVIDIA vGPU正在解决类似问题)。
MIG
NVIDIA MIG(Multi-Instance GPU)是英伟达推出的一种GPU虚拟化技术,旨在允许多个用户或工作负载共享单个物理GPU,通过硬件级别的分区实现资源隔离和高效利用。MIG于2020年随NVIDIA A100 GPU(基于Ampere架构)首次推出,随后在部分后续架构(如H100)中得到扩展。它主要面向高性能计算(HPC)、人工智能(AI)、深度学习和云服务等场景,支持将单个GPU划分为多个独立实例,每个实例具有独立的计算资源和内存。
MIG的优点
- 硬件级隔离::
- 与软件层面的GPU共享(如MPS)不同,MIG在硬件层面实现隔离,确保每个实例独立运行,避免资源竞争和故障传播,提供更高的安全性和稳定性。
- 高效资源利用:
- 允许多个用户或工作负载共享单个GPU,避免资源闲置。例如,一个A100 GPU可以同时运行多个小型AI模型推理任务或HPC作业。
- 接近原生性能::
- 由于是硬件分区,MIG实例的性能接近原生GPU性能,特别是在计算和内存隔离的情况下,性能开销极低。
- 与容器和虚拟化集成:
- MIG实例可以无缝分配给容器(如Docker)或虚拟机,支持Kubernetes等编排工具,简化云原生环境的部署。
- 错误隔离
- 一个MIG实例崩溃或出错不会影响其他实例,适合需要高可靠性的生产环境。
MIG的缺点
- 硬件限制:
- MIG目前仅支持部分高端GPU,如NVIDIA A100和H100(基于Ampere和Hopper架构),不支持消费级GPU(如GeForce系列)或较旧的专业级GPU。
- 不同GPU型号支持的MIG实例数量和配置文件不同,限制了灵活性。
- 静态资源分配:
- MIG实例的资源分配基于固定配置文件,无法动态调整。如果工作负载需求变化,需要销毁并重新创建实例,可能导致服务中断。
- 性能权衡:
- 尽管性能接近原生,但在某些情况下(如高负载任务或内存带宽竞争),多个MIG实例共享同一个物理GPU可能导致轻微性能下降。
vCUDA
在虚拟机内为物理GPU创建逻辑映像——即虚拟GPU。通过用户态拦截CUDA API,并将这些调用重定向到真实的物理GPU上执行计算。同时,在宿主机上运行vCUDA服务端,该服务端基于原生的CUDA运行时库和GPU驱动,负责接管虚拟GPU拦截的CUDA API,并调度相应的计算任务。
优点
- 介于CUDA的API是开源的,所以对于个人开发者来言是容易实现的,这也是目前来看市面上大多数厂商所采用的技术。
缺点
- CUDA库升级快,需要去不断的适配,再加上算力隔离需要不断的设计与优化算法,即使这样也无法提供精准的算力隔离限制,同时安全性低用户可以绕过限制。
当然,除了上述的方案还有其他的方案例如阿里云cGPU、腾讯云qGPU等
GPU虚拟化方案选择(个人)
同上述目前GPU虚拟化的主流方案,对于个人开发者来说,能够较易实现的方案主要有两个,PCIe直通模式和vCUDA,其它的方案如SR-IOV技术和MIG对于个人开发者来说是非常难以实现的,这两种方案只有英伟达这种硬件厂商才能实现,这也就是英伟达的NVIDIA vGPU、MIG,因为硬件厂商不会公布硬件编程接口。而对于PCIe直通模式和vCUDA,PCIe直通模式唯一的缺点就是硬件资源独占,无法做到多个VM共享,而vCUDA却能够做到多个VM共享一个GPU,再加上CUDA的API是开源的,所以目前来说vCUDA可能是个人开发者理想的选择。
目前开源的方案
在上节,明确说明了vCUDA可能是个人开发者理想的选择,目前为止,开源的方案有腾讯tkestack/vcuda-controller以及HAMI的HAMi-core ,这两者是继承关系,因为HAMI借鉴了不少vcuda-controller,目前能够使用的只有HAMi-core,而腾讯的vcuda-controller已经很久没有维护了。因此接下来,将介绍HAMi-core这个项目,去学习这个项目是如何实现vCUDA的,并希望能够构建属于自己的一套vCUDA。当然,你可以选择直接使用他们的项目,如果你只需要拿来能够使用,你可以直接去该项目下编译使用。
实现效果
上节介绍了一下vCUDA目前的开源项目,在正式的分析这个项目之前,可以先来看一下这个项目是如何使用的。
编译环境准备
NVIDIA驱动安装
首先在这个NVIDIA官方链接查找你显卡的驱动版本并下载:
以我NVIDIA GeForce GTX 1050为例
点击查找
选择最新的版本下载安装即可
安装之后运行nvidia-smi
# 如下所示表示安装成功
(base) root@ubuntu:~# nvidia-smi
Fri Apr 18 21:47:42 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.133.07 Driver Version: 570.133.07 CUDA Version: 12.8 |
|-----------------------------------------+------------------------+----------------------+
| 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 NVIDIA GeForce GTX 1050 Off | 00000000:01:00.0 Off | N/A |
| 19% 36C P0 N/A / 80W | 0MiB / 2048MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
(base) root@ubuntu:~#
CUDA安装(本地编译必须安装)
先在官网选择与NVIDIA驱动匹配的CUDA版本
如上nvidia-smi所示安装的NVIDIA驱动最高支持CUDA Version: 12.8,所以选择CUDA Toolkit 12.8.0下载安装即可
安装之后运行nvcc -V
# 如下所示表明安装成功
(base) root@ubuntu:~# nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2025 NVIDIA Corporation
Built on Wed_Jan_15_19:20:09_PST_2025
Cuda compilation tools, release 12.8, V12.8.61
Build cuda_12.8.r12.8/compiler.35404655_0
(base) root@ubuntu:~#
配置 Docker 守护进程以使用 NVIDIA 容器运行时
首先根据NVIDIA官方教程安装好所需软件
然后
vim /etc/docker/daemon.json
{
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
systemctl daemon-reload && systemctl restart docker
# 如下所示表面docker使用nvidia run
(base<