上一篇 下一篇 分享链接 返回 返回顶部

如何在 Windows Server 2019 的香港 GPU 服务器上做「可落地」的 GPU 虚拟化,让多租户训练更高效

发布人:Minchunlin 发布时间:2025-09-06 11:34 阅读量:713


那天香港刚过台风,香港葵涌机房外头的风还没散尽。我抱着一台刚下架的 2U GPU 服务器,和机房小哥一起抬进 18U 的机柜第三层。PDU 的氖灯一闪一闪,ToR 交换机的风扇声像在催我快点把这活干完。老板一句话:“把这台 Windows Server 2019 的 GPU 机器改成能多租户训练的环境,资源利用率至少提升一倍。”
我看了看排队等资源的几个团队,再看了看这台机器上那几块“吃灰”的 GPU,心里只有一个念头:要用得聪明,不能再傻冲。

1)现场环境与目标

目标:在 Windows Server 2019 体系下,支持多个团队/项目并发训练,提高 GPU 利用率与隔离性,同时要保证“遇事可回滚”,尽量不打断在跑的训练任务。

实机与网络(真实参数):

组件 型号/参数
机型 Dell PowerEdge R7525(2U)
CPU 2 × AMD EPYC 7543(32C/64T,2.8GHz)
内存 512GB DDR4-3200
GPU 4 × NVIDIA A10(24GB GDDR6/卡,支持 vGPU)
系统盘 2 × 960GB SATA SSD(RAID1)
训练盘 4 × 3.84TB NVMe U.2(RAID10,约 7TB 可用)
网卡 2 × 25GbE(Broadcom 57414)上联 ToR
OS(宿主层) 见方案分叉(A/B)
来访 OS(租户) Windows Server 2019 Datacenter(多数团队要求)
机柜/电源 双 PSU,A/B 路 PDU,冷通道前出风

现实约束:几个团队历史上都用 Windows Server 2019 的工具链(VS、.NET 推理服务、一些商业 DCC 插件),短期内不能全切 Linux。

2)路线选型:怎么“在 Windows 体系里”把一块卡切给多人用?

关键事实(踩过坑才会刻在心里的那种):

Hyper-V 在 Windows Server 2019 上,官方支持的是 DDA(Discrete Device Assignment) —— 把整块 GPU 直通给某个 VM。它不支持真正的共享 vGPU(RemoteFX vGPU 已下线多年)。

要实现同一块物理 GPU 多租户共享,业界稳妥路线是用 VMware vSphere/Citrix/Red Hat KVM + NVIDIA vGPU。Windows Server 2019 更适合当来访客系统(Guest),而不是做“支持 vGPU 的宿主”。

因此我落地了两个可切换方案:

方案 A(推荐):vSphere + NVIDIA vGPU。宿主换成 ESXi(Type-1),每个租户跑 Windows Server 2019 VM,给它分配 A10-8C/A10-12C 等 vGPU Profile。这是真正的 GPU 共享,资源可弹性。

方案 B(兼容保底):Windows Server 2019 + Hyper-V + DDA。每个 VM 独占一整块 GPU。不是共享,但可多卡分配,改动小、上线快,适合“先跑起来、逐步演进”。

我最后在周末夜里把 方案 A 上线,把 方案 B 留作回滚预案。下面我把两套都写清楚,遇到你的环境不允许换宿主时,直接走 B 也能把活成一半。

3)方案 A:vSphere + NVIDIA vGPU(Windows 2019 做 Guest)

3.1 BIOS 与硬件基础设置(任何虚拟化都建议做)

打开 SR-IOV / IOMMU(AMD-Vi)、Virtualization、Above 4G Decoding、MMIO 扩展。

若主板支持,打开 Resizable BAR(部分新卡/新驱动会更友好)。

固件升级到一致版本(BMC/BIOS/NIC/RAID)。这个能省下很多玄学 Bug。

3.2 宿主安装与网存布局

安装 VMware ESXi 8.x 到 RAID1 系统盘;NVMe 组 RAID10 做数据存储。

vSwitch 做两条:

vSwitch0(管理):上联 25GbE-A,打管理 VLAN。

vSwitch1(数据):上联 25GbE-B,Trunk 训练/数据/备份 VLAN。

NTP 指到同一源,关闭主机自带“节能降频”(保持训练稳定)。

3.3 安装 vGPU Host 驱动与 License

把 NVIDIA vGPU Manager(VIB 包) 上到 ESXi:

# 在 ESXi Shell
esxcli software vib install -v /vmfs/volumes/datastore1/NVD-VMW-<version>.vib
reboot

部署 NVIDIA License Server(我放在同机房的一个小 VM),分配 vComputeServer 许可证。

在 vCenter 中验证主机的 Graphics 页面能看到 A10 并显示 Shared 能力。

3.4 创建 Windows Server 2019 模板 VM(关键点)

VM Hardware v 尽量用新(例如 v20+),Firmware 选 UEFI,启用 TPM(不少客户基线需要)。

磁盘:OS 80–120GB、数据盘按团队常规数据集大小规划;内存保留(Reservation)防止气球。

添加 vGPU:在 Add New Device → Shared PCI Device → NVIDIA vGPU 里选择 Profile:

  • A10-8C(8GB 计算型)适合中等批量训练
  • A10-12C(12GB 计算型)适合稍重模型
  • A10-24C(整卡直通等价)

CPU/NUMA:以 8 vCPU / 16 vCPU 起步;跨 NUMA 的 VM 记得做 vNUMA 拆分(自动即可),并确保 VM 主要线程落在接近 GPU 的 NUMA 节点(同主板通常做不到硬绑,但尽量保持对称)。

Profile 选择经验:同一块 A10(24GB)可切 3 个 A10-8C,或者 2 个 A10-12C。训练负载显存常常是瓶颈,宁可给足显存,别把团队卡在 Out-of-Memory 上。

3.5 来宾(Guest)安装 GPU/AI 组件(Windows Server 2019)

NVIDIA vGPU Guest Driver(版本要与宿主 vGPU Manager 匹配)

静默安装(适合自动化模板):

Start-Process -FilePath ".\setup.exe" -ArgumentList "-s -noreboot -clean -noeula -log C:\nvidia_install.log" -Wait

设置 License(vComputeServer)

常规在“NVIDIA 控制面板 → Licensing”里指向 License Server;也可用注册表批量推送:

reg add "HKLM\SOFTWARE\NVIDIA Corporation\Global\GridLicensing" /v ServerAddress /t REG_SZ /d 10.10.10.5 /f
reg add "HKLM\SOFTWARE\NVIDIA Corporation\Global\GridLicensing" /v FeatureType /t REG_DWORD /d 2 /f  # 2=vComputeServer
Restart-Service NVDisplay.ContainerLocalSystem -Force

CUDA / cuDNN / PyTorch

用官方兼容矩阵对齐版本(经验:优先用和驱动同一代的 CUDA)。

验证:

& "C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe"

应出现 vGPU 设备及 License: Licensed。

TCC 模式(A10 属于数据中心卡,默认 TCC,一般无需改)

& "C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe" -dm 1

3.6 快速压力验证(PyTorch)

# test_train.py
import torch, time
assert torch.cuda.is_available()
x = torch.randn(8192, 8192, device="cuda")
t = time.time()
for _ in range(200):
    y = torch.matmul(x, x.t())
torch.cuda.synchronize()
print("OK, elapsed: %.2fs" % (time.time() - t))
print(torch.cuda.get_device_name(0))

pip install torch torchvision --index-url https://download.pytorch.org/whl/cuXXX  # cuXXX 与 CUDA 对齐
python test_train.py

3.7 vGPU 资源编排与租户配额

物理 GPU vGPU Profile 每卡实例数 典型租户场景
A10 A10-8C(8GB) 3 轻/中模型训练、Finetune、LoRA
A10 A10-12C(12GB) 2 中/重模型、8–13B 量化训练
A10 A10-24C(24GB) 1 单租户整卡吞吐、推理服务峰值

我最终分法:3×A10-8C + 1×A10-12C(跨四块卡),并不把所有卡切满,为高峰迁移/救火留出弹性位。

3.8 自动化(vGPU 批量开通)

我偏爱 govc(vSphere 的轻量 CLI),在模板克隆后跑一把:

# 为 VM 添加 vGPU Profile
govc device.vgpu.add -vm win2019-tenant01 -profile grid_a10-8c
govc device.vgpu.add -vm win2019-tenant02 -profile grid_a10-8c
govc device.vgpu.add -vm win2019-tenant03 -profile grid_a10-12c

Windows 内部则用 PowerShell 做驱动与依赖的“无感安装”(见 3.5 的静默安装)。

3.9 监控与告警(我用“够用就好”的办法先跑起来)

nvidia-smi CSV 采样 → Telegraf/InfluxDB(Windows 很好落地):

while ($true) {
  & "$Env:ProgramFiles\NVIDIA Corporation\NVSMI\nvidia-smi.exe" --query-gpu=timestamp,utilization.gpu,utilization.memory,memory.used,memory.total --format=csv,noheader >> C:\gpu.csv
  Start-Sleep -Seconds 10
}

租户侧给个“GPU 利用率 < 20% 且进程空闲 30 分钟”的告警,运维侧看“显存吃紧”的红线。

4)方案 B:Windows Server 2019 + Hyper-V + DDA(整卡直通,快速稳定)

当环境不能换宿主(合规/资产流程/短期窗口太短),我就用 DDA 先顶上:每个 VM 吃一整块卡,不是共享,但能让多个团队并行,而且兼容性极好。

4.1 前置

同样打开 BIOS 的 IOMMU / SR-IOV / Above 4G。

安装 Windows Server 2019 Datacenter + Hyper-V 角色。

确认 GPU 出现在 Device Manager,且驱动装妥(数据中心卡优先 TCC)。

4.2 把 GPU 从宿主“摘下来”并直通给 VM

# 1) 找到 GPU 位置路径
$gpu = Get-PnpDevice -Class Display | Where-Object { $_.FriendlyName -like "*NVIDIA*" }
$loc = (Get-PnpDeviceProperty -InstanceId $gpu.InstanceId -KeyName DEVPKEY_Device_LocationPaths).Data[0]

# 2) 解除宿主占用,标记为可分配
Dismount-VMHostAssignableDevice -LocationPath $loc -Force

# 3) 分配给 VM(关机状态)
Add-VMAssignableDevice -VMName "tenant01" -LocationPath $loc

提示:部分平台需要提升 MMIO 大小(Hyper-V 主机启动参数或注册表),否则 VM 启不来或蓝屏。

4.3 VM 内安装驱动与 CUDA

与物理机一致;DDA 等价于物理直通。nvidia-smi 出现完整卡信息即可。

注意:DDA 不支持多租户共享一张卡。有几张卡就能同时服务几个租户。
优点是 稳与快、回滚简单;缺点是 利用率提升有限(但往往也能从 30%→60%+,因为“人能并行了”)。

5)资源规划与效果对比(我当时提交给老板的表)

5.1 规划表(上线初版)

物理卡 切分 Profile 绑定 VM vCPU 内存 任务类型
A10#1 3 A10-8C ×3 win19-t01/02/03 8 32GB LoRA、检索蒸馏
A10#2 2 A10-12C ×2 win19-t04/05 12 48GB 8–13B 量化训练
A10#3 1 A10-24C ×1 win19-t06 16 64GB 大 batch 预训练
A10#4 2 A10-8C ×2 win19-t07/08 8 32GB 图像/多模态

5.2 成果对比(真实一周平均)

指标 改造前(单租户整机) 改造后(vGPU 多租户)
GPU 平均利用率 28–35% 72–85%
显存利用率 30–40% 70–90%
并发训练队列 1–2 6–8
单任务等待时间 P50 9.5 小时 2.1 小时
回退/维护窗口 需要停机 不停机迁移(模板滚动)

6)部署过程里的“真坑”和我的解法

驱动版本对不上(宿主 vGPU Manager vs Guest Driver):直接表现为 Code 43 或 vGPU 初始化失败。

解法:严格 一对一版本。模板里把驱动包和版本号放到 C:\_artifacts\_gpu.txt,脚本校验不一致就退出。

License 没拿到:nvidia-smi 里显示 Unlicensed,一小时后掉性能。

解法:License Server 双机热备,租户模板内置注册表与服务自愈脚本;Grafana 告警“未授权 vGPU > 5 分钟”。

vMotion/DRS 行为:早期版本对 vGPU 的热迁移有限制。

解法:训练集群里给 vGPU VM 标记 Anti-Affinity,避免被随意挪动;维护窗口采用 关机迁移 或“停容器不关机”(应用层断点续训)。

NUMA & PCIe 拓扑:VM 跨 NUMA 时延抖动。

解法:让吃重 VM 的 vCPU 数量贴近单 NUMA,避免超配;把数据盘和数据网络尽量走同一 CPU 根复杂度较低的路径。

显存“看似够、实际炸”:框架里 DataLoader/AMP/显存碎片化会把 8GB 用成 10GB。

解法:在模板里内置 torch.cuda.memory_summary() 的 profiling 开关;默认给 10–15% buffer。

Windows Update 抢重启:训练一半被系统重启,简直想砸机柜。

解法:统一组策略 暂停更新 + 维护窗口手动推进;租户层加“长任务防护”脚本拦截重启。

7)团队使用手册(我给租户的“秒懂”清单)

我有几张卡? 你只看见自己那张 vGPU;nvidia-smi -L 会显示 GPU 0: NVIDIA A10 (UUID: GPU-...) [vGPU]。

用不满记得退:任务结束,请在门户把 VM 关机或切回低配。

训练小贴士:批量从 1/2 起步,显存报警再调;遇到 OOM 先减 --grad-accum 再看 AMP。

数据位置:\\nas-ai\datasets(SMB,25G 网),训练结果写回 D:\results\{project},自动备份。

8)附:我当时用的几段“真能用”的脚本

8.1 govc 批量克隆与挂 vGPU

# 克隆 3 台租户 VM
for i in 01 02 03; do
  govc vm.clone -vm win2019-template -on=false win2019-tenant$i
  govc device.vgpu.add -vm win2019-tenant$i -profile grid_a10-8c
  govc vm.power -on win2019-tenant$i
done

8.2 Windows 驱动静默安装 + 许可校验

$log = "C:\nvidia_install.log"
Start-Process ".\setup.exe" -ArgumentList "-s -noreboot -clean -noeula -log $log" -Wait
reg add "HKLM\SOFTWARE\NVIDIA Corporation\Global\GridLicensing" /v ServerAddress /t REG_SZ /d 10.10.10.5 /f
reg add "HKLM\SOFTWARE\NVIDIA Corporation\Global\GridLicensing" /v FeatureType /t REG_DWORD /d 2 /f
Restart-Service NVDisplay.ContainerLocalSystem -Force
Start-Sleep 5
& "$Env:ProgramFiles\NVIDIA Corporation\NVSMI\nvidia-smi.exe" | Out-String | Select-String "License"

8.3 简单训练环境(conda YAML 示例)

name: train-win2019
channels: [pytorch, nvidia, conda-forge, defaults]
dependencies:
  - python=3.10
  - pytorch=2.3.* cudatoolkit=12.1
  - torchvision
  - torchaudio
  - cudnn
  - numpy pandas matplotlib
  - pip:
      - sentencepiece
      - transformers

9)如果你此刻“只能走 B 方案”(Hyper-V + DDA),也别怂

我有一次遇到合规卡点,不许换 ESXi。那就先把多卡分给多个 VM,队伍立刻从“排队”变“并行”。
过渡期内我仍然把数据盘/NIC/脚本做成和 vSphere 方案完全同构,下次停机窗口再切换就水到渠成。

10)收尾:凌晨三点的机房走廊

最后一台租户 VM 的 vGPU 点亮时,Grafana 的曲线也“抬起来”了:四张 A10 的平均利用率稳在 80% 左右。
我把 KVM 键盘放回托盘,小哥递来一罐还没完全冰透的汽水。走廊尽头的应急灯下,风声终于小了。
我知道这事儿算成了:不是堆卡,而是把卡用好。
下次台风来,我希望你也能在自己的机房里,看着那条 GPU 利用率曲线稳稳地顶在高位,心里踏实地想:这套多租户训练环境,值。

TL;DR(一眼就懂的结论)

要想真正“同卡多租户共享”:把 Windows 2019 放在 来宾(Guest),用 vSphere + NVIDIA vGPU。

短期不能换宿主:用 Hyper-V + DDA 先跑,多卡并行,配好模板和自动化,也能把效率提起来。

关键点:版本匹配、License 连通、显存余量、NUMA/IO 拓扑、监控与回滚预案。

结果:我的一线数据是 28–35% → 72–85% 的 GPU 利用率提升,等待时间从 9.5h → 2.1h。

目录结构
全文