封面来源:NUMA
需求分析
-
课题组现有一台工作站,用于运行ansys fluent仿真;
-
由于多核并行存在的边际效应,使用中发现仅使用一半的核即可达到近似的计算速度.
-
拟将一台物理机拆分为两台虚拟机,供两人同时使用.
硬件配置与网络环境
- 硬件配置:课题组现有工作站.
| 硬件类型 | 名称 |
|---|---|
| CPU | AMD TR 3990X (64核128线程) |
| 主板 | 华硕TRX 40 PRO S |
| 内存 | 128G-DDR4 2133 |
| 显卡 | 3060Ti |
| 硬盘 | 1× 1T SSD + 1× 4T SSD |
- 网络环境:局域网环境,配置流程中需要上游路由为虚拟机分配静态内网地址.
整体配置思路
- 系统架构:底层虚拟环境为PVE,开放使用的工作终端为2台Win10虚拟机;
- 磁盘分区
| 物理盘序号 | 分区大小 | 分区类型 | 分区作用 |
|---|---|---|---|
| 1 (1TB) | 30G | LVM | PVE系统+ISO镜像 |
| 1 (1TB) | 800G | LVM-thin | 作为两台虚拟机的系统盘(C:) |
| 2 (4TB) | 4T | LVM-thin | 作为两台虚拟机的数据盘(D:) |
搭建流程
PVE虚拟环境安装
- 安装PVE 9.1版本;
- 在选择安装磁盘时,务必在选项中设置”MAX ROOT”参数:
- 这一选项限制了PVE系统所占用的分区大小,可留下更多空间给虚拟机;
- 一般30GB完全足够,不够用后续是可以扩展的.
- 其它安装流程较为常规,不赘述.
TIP限制PVE分区大小,为虚拟机留下更多空间.
PVE初始配置
- 换源&包更新:参考与,将PVE源与Debian源更换到国内1;使用以下命令进行包更新.
apt update && apt upgrade -y- 硬盘分区:将4TB硬盘进行擦除与格式化,创建新的thinpool.
NOTE潜在优化:图中的thinpool创建方式未给SSD留够OP,建议给SSD空出15%左右的未分区空间供主控使用.

优化配置
-
进行NUMA初始配置,需要在安装虚拟机前完成.
-
NUMA:“Non-uniform memory access”,非一致内存访问.
-
主要目的:提升访存性能.
-
工作原理:将系统内存划分为多块,将各块分配给访问延迟最低的CPU核心,实现整体访存性能提升;跨NUMA节点的内存访问相对很慢.
-
适用性分析
- 本工作站分为两台独立虚拟机,相互之间不会进行内存访问;
- 将原机器分为两个NUMA节点,将每一台虚拟机分别绑定到其中一个节点,可以规避跨NUMA节点访存的劣势,最大化内存性能;
- 虽然本机只有单颗CPU,但3990X CPU中本就分为多个CCD,可以分为多个NUMA节点.
-
配置流程
-
配置BIOS:在主板BIOS中修改NUMA设置.
- 该选项一般被称为”NUMA”、“Memory Node”或者”Memory Configuration”.
- 一般可以设置为NPS1/NPS2/NPS4,代表每个插槽的节点数(Node per socket).
- 此处需要两个NUMA节点,仅有一个CPU,选择”NPS2”.
- 重启进入PVE,运行如下命令查询NUMA状态;对应的输出如下,说明该系统已被分为两个NUMA节点及各自对应的CPU核编号.
Terminal window lscpu | grep -i numaNUMA node(s): 2
NUMA node0 CPU(s): 0-31,64-95
NUMA node1 CPU(s): 32-63,96-127 -
安装&使用numactl: numactl是一个NUMA策略监控管理工具,在PVE下使用如下命令安装与初始使用.
- 可以查看到各node间的距离,可以发现跨节点内存访问的”距离”为12,节点内的为10.
apt update && apt install numactl -y && numactl --hardwareavailable: 2 nodes (0-1)
node 0 cpus : …
node 0 size: xxx MB
node 0 free: xxx MB
node1 …
node distances:
node 0 1
0: 10 12
1: 12 10
- NUMA前期准备完成,下一步工作在虚拟机创建后进行.
优化配置:大页内存
- 进行大页内存的初始配置,需要在安装虚拟机前完成.
- 主要目的:提升访存性能.
- 工作原理:将linux中的默认4KB page提升到1GB,大大减小页表体积,降低访存cache miss的可能性,提升性能.
- 潜在问题:本文使用的内存分配方法会在PVE系统启动时即将大页内存分配好,导致这一部分内存持续被占用,无法被PVE系统/其它虚拟机动态使用,但在本文场景中影响不大.
- 配置流程
-
编辑grub
- 打开grub文件
nano /etc/default/grub
- 修改
GRUB_CMDLINE_LINUX_DEFAULT行,在现有参数后添加:default_hugepagesz=1G hugepagesz=1G hugepages=120(其中120是大页数量,按实际内存数量修改).记得给PVE系统预留空间.
IMPORTANT
大页数量不可等于系统总内存,一定要为PVE系统预留!否则会导致系统反复重启,只能重装.
-
结合NUMA节点分配内存块
- 通过以下命令,在PVE系统启动时将大页平均分配到两个NUMA节点.其中的60是每节点大页数量,为①中总页数的一半.
Terminal window echo "echo 60 > /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages" | tee -a /etc/rc.localecho "echo 60 > /sys/devices/system/node/node1/hugepages/hugepages-1048576kB/nr_hugepages" | tee -a /etc/rc.localupdate-grub # 更新grubreboot # 重启系统 -
确认大页内存已分配
- 系统重启后,使用以下命令查看各个节点上的大页数量,应当与上一步的设置一致.
Terminal window cat /sys/devices/system/node/node*/hugepages/hugepages-1048576kB/free_hugepages预期输出:
60 60
-
大页内存前期准备完成,下一步工作在虚拟机创建后进行.
创建虚拟机
- 以下步骤用于创建虚拟终端.
- 将Windows 10 ISO镜像和VirtIO驱动2上传到PVE系统.
-
点击PVE界面右上角的创建虚拟机选项.
- 常规界面
- 操作系统界面
- 系统界面:将TPM存储与EFI存储设定到local_lvm卷,与虚拟Windows安装到同一块物理SSD上.
- 磁盘界面:将scsi0的磁盘大小设置为400G,存储选择在local_lvm;左下角点击”添加”,新scsi1磁盘的存储选择在硬盘分区一节新建的存储池,大小设置为1800G.
TIP
潜在优化:此处也可先设置scsi0大小为128G,且不添加scsi1;待系统整备完成后,可以先备份一个最小系统镜像,再扩展分区.
- CPU界面:两台虚拟机设置略有差别,需要绑定到不同的CPU核心.
- 内存界面:容量与大页大小保持一致(如50个大页,就填写50*1024=51200 MB),取消勾选Ballooning.
- 网络界面:保持默认,可按需设置虚拟网卡MAC地址.
- 创建虚拟机,创建后先不要启动,需要进行额外配置.
-
额外配置
- 修改PVE后台虚拟机配置文件.
- 打开位于
/etc/pve/qemu-server文件夹下的虚拟机配置文件,文件名为”<vm_id>.conf”,其中vm_id为上一步”常规”选项卡中的虚拟机ID. - 参考下图设置,只要修改有注释的行,如果对应行不存在可以自行添加.
- 验证配置正确性.
- 启动虚拟机后,按序执行下述指令;如得到期待结果,则说明NUMA与大页内存配置成功.
# 查询大页剩余grep "" /sys/devices/system/node/node*/hugepages/hugepages-1048576kB/free_hugepages# 在虚拟机启动后,两个node上的hugepages计数都应降为0.
# 验证内存-NUMA节点绑定情况# 获取虚拟机PID: 将 101 替换为实际VM_IDps aux | grep "/usr/bin/kvm -id 101" | grep -v grep | awk '{print $2}' # 返回的数字为虚拟机PID# 查看内存使用情况numastat -p 12345 # 12345是刚刚查询到的虚拟机PID# 如果配置成功,该虚拟机的绝大部分内存会集中在其对应的node上,只有很少一部分跨node.# 典型的情况如下.# Per-node process memory usage (in MBs) for PID 31529 (kvm)# Node 0 Node 1 Total# --------------- --------------- ---------------# Huge 0.00 59392.00 59392.00# Heap 0.00 27.23 27.23# Stack 0.00 0.72 0.72# Private 13.46 63.11 76.57# ---------------- --------------- --------------- ---------------# Total 13.46 59483.07 59496.52- 安装虚拟机操作系统.
- 按照常规Windows安装流程即可.在选择安装磁盘步骤,需要先加载VirtIO带”w10”字样的驱动,才能找到磁盘.
TIP在选择安装磁盘步骤,选择对应的VirtIO驱动来找到虚拟磁盘.
进行USB直通
- 工作目的:使用U盘向虚拟机直接传输数据.
- 工作思路:直通USB控制器直通到虚拟机.
- 技术选型:常见的USB直通方案有按设备直通、按控制器直通.
- 按设备直通:在PVE中选择”硬件->添加->USB设备”进行添加.
- 按控制器直通:在PVE中选择”硬件->添加->PCI设备”进行添加.
- 其中,前者设置简单,不需要重启 PVE,但是使用新U盘时由于U盘ID变化,需要重新操作;后者直接让虚拟机识别原生的 USB 控制器,无性能损耗,且只要将U盘插到对应的数个物理接口上即能自动识别.本文选用按控制器直通方案.
正常流程
- 硬件启用iommu:进入主板BIOS.
- Intel: 打开VT-d / Virtualization Technology.
- AMD: 打开iommu / AMD-Vi / SVM Mode.
- 软件启用iommu
# 打开pve的grub配置文件vi /etc/default/grub# 在原有GRUB_CMDLINE_LINUX_DEFAULT参数后添加:# intel :"intel_iommu=on iommu=pt"# amd: "amd_iommu=on iommu=pt"# 修改后的选项可能如:"quiet default_hugepagesz=1G hugepagesz=1G hugepages=116 amd_iommu=on iommu=pt"update-grub # 更新grub
# 加载直通模块echo "vfio" | tee -a /etc/modules-load.d/vfio.confecho "vfio_iommu_type1" | tee -a /etc/modules-load.d/vfio.confecho "vfio_pci" | tee -a /etc/modules-load.d/vfio.confecho "vfio_virqfd" | tee -a /etc/modules-load.d/vfio.confupdate-initramfs -u -k all
# 重启并检查是否成功.rebootdmesg | grep -e DMAR -e IOMMU # 如果结果里有"IOMMU enabled"或者"Detected AMD IOMMU #0"等字样说明成功.- 查看硬件分组
lspci -nnk | grep USB # 查看USB硬件# 可能的返回值# 03:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Starship USB 3.0 Host Controller [1022:148c]# 22:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Starship USB 3.0 Host Controller [1022:148c]# 44:00.1 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Matisse USB 3.0 Host Controller [1022:149c]# 44:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Matisse USB 3.0 Host Controller [1022:149c]# 说明该系统具有4个USB控制器,总线地址为03:00.3等.
# 但部分控制器可能共享IOMMU分组,这说明它们的物理电路相捆绑,只能按组直通,不能直通一半/分给两台VM.# 使用以下命令确认,最后的总线编号参照上方返回值修改.printf '%s\n' /sys/kernel/iommu_groups/*/devices/* | while read -r d; do echo "Group ${d%/devices/*}; ${d##*/}; $(lspci -nns ${d##*/})"; done | grep -E "03:00.3|22:00.3|44:00.1|44:00.3"# 可能的返回值如下:# Group /sys/kernel/iommu_groups/24; 0000:44:00.1; 44:00.1 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Matisse USB 3.0 Host Controller [1022:149c]# Group /sys/kernel/iommu_groups/24; 0000:44:00.3; 44:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Matisse USB 3.0 Host Controller [1022:149c]# Group /sys/kernel/iommu_groups/43; 0000:22:00.3; 22:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Starship USB 3.0 Host Controller [1022:148c]# Group /sys/kernel/iommu_groups/60; 0000:03:00.3; 03:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Starship USB 3.0 Host Controller [1022:148c]# 注意到开头/sys/kernel/iommu_groups/xx中的xx是IOMMU分组,说明44:00开头的两个控制器在同一个IOMMU组,无法拆分.# 同时,结尾的[1022:149c]是对应控制器的ids编号,处理意外情况时有用.- 映射物理接口
# 将主板物理接口与总线编号进行对应.# 首先将接口与总线进行对应.watch -n 1 "lsusb -t"# 先运行上述指令,再准备一个U盘,依次序插入主板的各个物理接口.# 在插入后,某个总线上会多出一个设备,此即该物理口所对应的USB总线.# 反复操作,形成一张对应表,如:# 物理接口编号 USB总线编号# 前面板1号口 USB1# 前面板2号口 USB1# 后面板一号口 USB2# ...
# 对应USB Bus与PCI地址.grep . /sys/bus/usb/devices/usb*/../../uevent# 其返回结果如下:# ....(很多其它信息)# /sys/bus/usb/devices/usb1/../../uevent:PCI_SLOT_NAME=0000:03:00.3 # usb1的PCI总线编号# ....# 将每个usb bus与PCI总线的对应关系记录下来,如下:# 物理接口编号 USB总线编号 对应PCI总线编号# 前面板1号口 USB1 0000:00:08.1# 前面板2号口 USB1 0000:00:08.1# 后面板一号口 USB2 0000:20:08.1# ...
# 形成对应表后,可以进行下一步;但有时候会找不到具有对应编号的设备,请参阅 [31m"意外情况-找不到具有对应PCI ID的设备"[0m 一节.- 控制器直通
- 打开PVE后台网页,打开对应虚拟机->硬件->添加->PCI设备选项卡.
- 直通对应的控制器后,其下挂载的所有物理USB接口都会直接归于该虚拟机管理.
- **完成!**只需将U盘插入直通控制器控制的物理USB口,即可直连至虚拟机~
意外情况
-
意外1:找不到具有对应PCI ID的设备
-
问题描述:在某些情况下,根据第三步的
PCI_SLOT_NAME,找不到对应的PCIE设备. -
问题原理:在 AMD 架构下,
PCI_SLOT_NAME一般是USB 控制器的”父亲”(PCIe 桥/根端口),而不是控制器本身. -
解决方案
Terminal window # 列举PCI设备树.lspci -t# 典型输出如下#-+-[0000:00]-+-00.0# ... 一堆设备# | +-08.1-[03]--+-00.0# | | \-00.3# ... 一堆设备# 这里可以看到,PCI_SLOT_NAME(0000:00:08.1)下面挂着(03:00.3),后者在PVE的PCIE设备列表中可以找到.# 转而选择对应的子Controller即可.
-
-
意外2:直通后系统异常重启,或者直通成功但没效果
-
问题原理
平台下,宿主机的驱动可能存在bug,导致宿主机驱动(xhci_hcd)没有释放设备,虚拟机驱动(vfio-pci)便无法获取设备. -
解决方案:禁止宿主机加载USB驱动.
IMPORTANT
执行该步操作后,将只能通过网络界面访问PVE后台,直连PVE物理机的USB键盘/鼠标可能失效,请谨慎操作.
-
操作步骤
-
# 参考"查看硬件分组"一节,找到要直通的USB控制器的ids编号(以1022:148c为例).# 1.强制绑定到虚拟机驱动(vfio-pci)# 编辑/创建配置文件vim /etc/modprobe.d/vfio.conf# 在文件中输入以下内容options vfio-pci ids=1022:148c
# 先重启检查一下这样行不行.update-initramfs -u -k all && reboot
# 重启后,在终端查询lspci -nnk -s 22:00.3 # 22:00.3是对应的USB Controller编号,不一定是PCI_SLOT_NAME!# 在输出中找到Kernel driver in use一行,如果显示vfio-pci则无需执行后续操作,进虚拟机看效果即可.
# [31m最终备选方案[0m :如果仍显示xhci,则需进行下面的屏蔽操作.vim /etc/modprobe.d/pve-blacklist.conf# 添加以下行blacklist xhci_hcdblacklist xhci_pci
# 更新内核并重启update-initramfs -u -k all && reboot# 重新查询,99.9%的概率都能成功变为vfio-pci.lspci -nnk -s 22:00.3改进思路
本次配置虽然达到了目的,但也存在一些问题.
- 问题1:未给SSD留OP空间.
- 在创建lvm-thin分区时使用CLI操作,特意留下空闲空间.
- 问题2:未留存装好工程软件的最小系统镜像,不方便恢复.
- 遵循”创建小硬盘->安装软件->全盘备份->硬盘扩容”的流程安装新系统,方便系统恢复.