目录
一、简介
与主机中的物理 CPU 非常相似,vCPU 对于虚拟机 (VM) 性能至关重要。因此,优化 vCPU 可能会对 VM 的资源效率产生重大影响。要优化 vCPU,请执行以下操作:
1、调整分配给 VM 的主机 CPU 数量。您可以使用 CLI 或 Web 控制台执行此操作。
2、确保 vCPU 模型与主机的 CPU 模型对齐。例如,要将 testguest1 VM 设置为使用主机的 CPU 模型,请执行以下操作:
virt-xml testguest1 --edit --cpu host-model
在 ARM 64位平台 系统上,使用 .--cpu host-passthrough
4、如果主机使用非一致性内存访问 (NUMA),则还可以为其 VM 配置 NUMA。这会将主机的 CPU 和内存进程尽可能紧密地映射到 VM 的 CPU 和内存进程。实际上,NUMA 优化为 vCPU 提供了对分配给 VM 的系统内存的更简化的访问,这可以提高 vCPU 的处理效率。
1.1 使用命令行界面添加和删除虚拟 CPU
要提高或优化虚拟机 (VM) 的 CPU 性能,您可以添加或删除分配给 VM 的虚拟 CPU (vCPU)。
在正在运行的 VM 上执行时,这也称为 vCPU 热插拔和热拔出。但是,请注意,RHEL 9 不支持 vCPU 热拔出,Red Hat 强烈建议不要使用热拔插。
先决条件
可选:查看目标 VM 中 vCPU 的当前状态。例如,要显示 testguest VM 上的 vCPU 数量,请执行以下操作:
# virsh vcpucount testguest
maximum config 4
maximum live 2
current config 2
current live 1
此输出指示 testguest 当前正在使用 1 个 vCPU,并且可以将另外 1 个 vCPu 热插拔以提高 VM 的性能。但是,重新启动后,testguest 使用的 vCPU 数量将更改为 2 个,并且可以再热插拔 2 个 vCPU。
具体过程
1、调整可以连接到 VM 的最大 vCPU 数,该数将在 VM 下次启动时生效。
例如,要将 testguest VM 的最大 vCPU 计数增加到 8,请执行以下操作:
virsh setvcpus testguest 8 --maximum --config
请注意,最大值可能受 CPU 拓扑、主机硬件、虚拟机管理程序和其他因素的限制。
2、调整连接到 VM 的当前 vCPU 数量,直至达到上一步中配置的最大值。例如:
要将连接到正在运行的 testguest VM 的 vCPU 数量增加到 4,请执行以下操作:
virsh setvcpus testguest 4 --live
这将提高 VM 的性能和 testguest 的主机负载占用量,直到 VM 下次启动。
-
要将连接到 testguest VM 的 vCPU 数量永久减少到 1,请执行以下操作:
virsh setvcpus testguest 1 --config
这会降低 VM 的性能和 testguest 下次启动后的主机负载占用情况。但是,如果需要,可以将其他 vCPU 热插拔到 VM,以暂时提高其性能。
验证
-
确认 VM 的 vCPU 的当前状态反映了您的更改。
# virsh vcpucount testguest
maximum config 8
maximum live 4
current config 1
current live 4
1.2 在虚拟机中配置NUMA
以下方法可用于配置 RHEL 9 主机上虚拟机 (VM) 的非一致性内存访问 (NUMA) 设置。
先决条件
-
主机是与 NUMA 兼容的计算机。要检测是否是这种情况,请使用
virsh nodeinfo
命令并查看NUMA cell(s)
以下行:
# virsh nodeinfo
CPU model: x86_64
CPU(s): 48
CPU frequency: 1200 MHz
CPU socket(s): 1
Core(s) per socket: 12
Thread(s) per core: 2
NUMA cell(s): 2
Memory size: 67012964 KiB
如果该行的值为 2 或更大,则主机与 NUMA 兼容。
1.3 详细步骤
为了便于使用,您可以使用自动化实用程序和服务来设置 VM 的 NUMA 配置。但是,手动 NUMA 设置更有可能产生显著的性能改进。
自动方法
-
将 VM 的 NUMA 策略设置为
Preferred
。例如,要对 testguest5 VM 执行此操作,请执行以下操作:
virt-xml testguest5 --edit --vcpus placement=auto
virt-xml testguest5 --edit --numatune mode=preferred
在主机上启用自动 NUMA 平衡:
echo 1 > /proc/sys/kernel/numa_balancing
启动numad
服务以自动将 VM CPU 与内存资源对齐。
systemctl start numad
手动方法
1、将特定 vCPU 线程固定到特定主机 CPU 或 CPU 范围。这在非 NUMA 主机和 VM 上也是可能的,建议将其作为提高 vCPU 性能的安全方法。
例如,以下命令将 testguest6 VM 的 vCPU 线程 0 固定到 5,分别托管 CPU 1、3、5、7、9 和 11:
# virsh vcpupin testguest6 0 1
# virsh vcpupin testguest6 1 3
# virsh vcpupin testguest6 2 5
# virsh vcpupin testguest6 3 7
# virsh vcpupin testguest6 4 9
# virsh vcpupin testguest6 5 11
之后,您可以验证此操作是否成功:
# virsh vcpupin testguest6
VCPU CPU Affinity
----------------------
0 1
1 3
2 5
3 7
4 9
5 11
2、固定 vCPU 线程后,您还可以将与指定 VM 关联的 QEMU 进程线程固定到特定主机 CPU 或 CPU 范围。例如,以下命令将 testguest6 的 QEMU 进程线程固定到 CPU 13 和 15,并验证此操作是否成功:
# virsh emulatorpin testguest6 13,15
# virsh emulatorpin testguest6
emulator: CPU Affinity
----------------------------------
*: 13,15
3、最后,您还可以指定将哪些主机 NUMA 节点专门分配给特定 VM。这可以提高 VM 的 vCPU 的主机内存使用率。例如,以下命令将 testguest6 设置为使用主机 NUMA 节点 3 到 5,并验证此操作是否成功:
# virsh numatune testguest6 --nodeset 3-5
# virsh numatune testguest6
注意
为了获得最佳性能结果,建议使用上面列出的所有手动优化方法
1.4 vCPU性能调优方案示例
为了获得最佳的 vCPU 性能,Red Hat 建议同时使用手动vcpupin
、emulatorpin
和numatune
设置,例如在以下场景中。
1.4.1 场景
-
您的主机具有以下硬件特性:
- 2 个 NUMA 节点
- 每个节点上有 3 个 CPU 核心
- 每个核心上有 2 个线程
这种机器virsh nodeinfo的输出看起来类似于:
# virsh nodeinfo
CPU model: x86_64
CPU(s): 12
CPU frequency: 3661 MHz
CPU socket(s): 2
Core(s) per socket: 3
Thread(s) per core: 2
NUMA cell(s): 2
Memory size: 31248692 KiB
-
你打算将现有 VM 修改为具有 8 个 vCPU,这意味着它不适合单个 NUMA 节点。
因此,您应在每个 NUMA 节点上分配 4 个 vCPU,并使 vCPU 拓扑尽可能与主机拓扑相似。这意味着,作为给定物理 CPU 的同级线程运行的 vCPU 应固定到同一内核上的主机线程。有关详细信息,请参阅下面的解决方案:
1.4.2 解决方案
1、获取有关主机拓扑的信息:
#virsh capabilities
输出应包括一个部分,该部分类似于以下内容:
<topology>
<cells num="2">
<cell id="0">
<memory unit="KiB">15624346</memory>
<pages unit="KiB" size="4">3906086</pages>
<pages unit="KiB" size="2048">0</pages>
<pages unit="KiB" size="1048576">0</pages>
<distances>
<sibling id="0" value="10" />
<sibling id="1" value="21" />
</distances>
<cpus num="6">
<cpu id="0" socket_id="0" core_id="0" siblings="0,3" />
<cpu id="1" socket_id="0" core_id="1" siblings="1,4" />
<cpu id="2" socket_id="0" core_id="2" siblings="2,5" />
<cpu id="3" socket_id="0" core_id="0" siblings="0,3" />
<cpu id="4" socket_id="0" core_id="1" siblings="1,4" />
<cpu id="5" socket_id="0" core_id="2" siblings="2,5" />
</cpus>
</cell>
<cell id="1">
<memory unit="KiB">15624346</memory>
<pages unit="KiB" size="4">3906086</pages>
<pages unit="KiB" size="2048">0</pages>
<pages unit="KiB" size="1048576">0</pages>
<distances>
<sibling id="0" value="21" />
<sibling id="1" value="10" />
</distances>
<cpus num="6">
<cpu id="6" socket_id="1" core_id="3" siblings="6,9" />
<cpu id="7" socket_id="1" core_id="4" siblings="7,10" />
<cpu id="8" socket_id="1" core_id="5" siblings="8,11" />
<cpu id="9" socket_id="1" core_id="3" siblings="6,9" />
<cpu id="10" socket_id="1" core_id="4" siblings="7,10" />
<cpu id="11" socket_id="1" core_id="5" siblings="8,11" />
</cpus>
</cell>
</cells>
</topology>
2、自选:使用适用的工具和实用工具测试 VM 的性能。
3、在主机上设置并挂载 1 GiB 大页面:
注意
1 GiB 的大页面在某些架构和配置(例如 ARM 64 主机)上可能不可用。
a.将以下行添加到主机的内核命令行中:
default_hugepagesz=1G hugepagesz=1G
b.使用以下内容创建
/etc/systemd/system/hugetlb-gigantic-pages.service
文件:
[Unit]
Description=HugeTLB Gigantic Pages Reservation
DefaultDependencies=no
Before=dev-hugepages.mount
ConditionPathExists=/sys/devices/system/node
ConditionKernelCommandLine=hugepagesz=1G
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/etc/systemd/hugetlb-reserve-pages.sh
[Install]
WantedBy=sysinit.target
c.使用以下内容创建/etc/systemd/hugetlb-reserve-pages.sh
文件:
#!/bin/sh
nodes_path=/sys/devices/system/node/
if [ ! -d $nodes_path ]; then
echo "ERROR: $nodes_path does not exist"
exit 1
fi
reserve_pages()
{
echo $1 > $nodes_path/$2/hugepages/hugepages-1048576kB/nr_hugepages
}
reserve_pages 4 node1
reserve_pages 4 node2
这将从 node1 保留 4 个 1GiB 大页面,从 node2 保留 4 个 1GiB 大页面。
d.使在上一步中创建的脚本可执行:
chmod +x /etc/systemd/hugetlb-reserve-pages.sh
e. 在启动时启用大页面预留:
systemctl enable hugetlb-gigantic-pages
4、使用以下virsh edit
命令编辑要优化的 VM 的 XML 配置,在此示例中为 super-VM:
virsh edit super-vm
5、按以下方式调整 VM 的 XML 配置:
a.将 VM 设置为使用 8 个静态 vCPU。使用<vcpu/>
元素来执行此操作。
b.将每个 vCPU 线程固定到它在拓扑中镜像的相应主机 CPU 线程。为此,请使用<cputune>
部分中的<vcpupin/>
元素。
请注意,如上面的virsh capabilities
实用程序所示,主机 CPU 线程在其各自的核心中不是按顺序排序的。此外,应将 vCPU 线程固定到同一 NUMA 节点上的最高可用主机核心集。有关表说明,请参阅下面的“示例拓扑”部分。
步骤 a. 和 b. 的 XML 配置可能类似于:
<cputune>
<vcpupin vcpu='0' cpuset='1'/>
<vcpupin vcpu='1' cpuset='4'/>
<vcpupin vcpu='2' cpuset='2'/>
<vcpupin vcpu='3' cpuset='5'/>
<vcpupin vcpu='4' cpuset='7'/>
<vcpupin vcpu='5' cpuset='10'/>
<vcpupin vcpu='6' cpuset='8'/>
<vcpupin vcpu='7' cpuset='11'/>
<emulatorpin cpuset='6,9'/>
</cputune>
c.将 VM 设置为使用 1 GiB 大页面:
<memoryBacking>
<hugepages>
<page size='1' unit='GiB'/>
</hugepages>
</memoryBacking>
将 VM 的 NUMA 节点配置为使用主机上相应 NUMA 节点的内存。为此,请使用以下<numatune/>
部分中的<memnode/>
元素:
<numatune>
<memory mode="preferred" nodeset="1"/>
<memnode cellid="0" mode="strict" nodeset="0"/>
<memnode cellid="1" mode="strict" nodeset="1"/>
</numatune>
确保 CPU 模式设置为host-passthrough
,并且 CPU 在passthrough
模式中使用缓存:
<cpu mode="host-passthrough">
<topology sockets="2" cores="2" threads="2"/>
<cache mode="passthrough"/>
在 ARM 64 系统上,省略该行。<cache mode="passthrough"/>
1.4.3 验证
1、确认生成的 VM 的 XML 配置包含类似于以下内容的部分:Confirm that the generated XML configuration of the VM includes a section similar to the following:
[...]
<memoryBacking>
<hugepages>
<page size='1' unit='GiB'/>
</hugepages>
</memoryBacking>
<vcpu placement='static'>8</vcpu>
<cputune>
<vcpupin vcpu='0' cpuset='1'/>
<vcpupin vcpu='1' cpuset='4'/>
<vcpupin vcpu='2' cpuset='2'/>
<vcpupin vcpu='3' cpuset='5'/>
<vcpupin vcpu='4' cpuset='7'/>
<vcpupin vcpu='5' cpuset='10'/>
<vcpupin vcpu='6' cpuset='8'/>
<vcpupin vcpu='7' cpuset='11'/>
<emulatorpin cpuset='6,9'/>
</cputune>
<numatune>
<memory mode="preferred" nodeset="1"/>
<memnode cellid="0" mode="strict" nodeset="0"/>
<memnode cellid="1" mode="strict" nodeset="1"/>
</numatune>
<cpu mode="host-passthrough">
<topology sockets="2" cores="2" threads="2"/>
<cache mode="passthrough"/>
<numa>
<cell id="0" cpus="0-3" memory="2" unit="GiB">
<distances>
<sibling id="0" value="10"/>
<sibling id="1" value="21"/>
</distances>
</cell>
<cell id="1" cpus="4-7" memory="2" unit="GiB">
<distances>
<sibling id="0" value="21"/>
<sibling id="1" value="10"/>
</distances>
</cell>
</numa>
</cpu>
</domain>
2、可选,使用适用的工具和实用工具测试 VM 的性能,以评估 VM 优化的影响。
示例拓扑
主机拓扑
CPU 线程 | 0 | 3 | 1 | 4 | 2 | 5 | 6 | 9 | 7 | 10 | 8 | 11 | ||
核心 | 0 | 1 | 2 | 3 | 4 | 5 | ||||||||
插座 | 0 | 1 | ||||||||||||
NUMA 节点 | 0 | 1 |
VM拓扑
vCPU 线程 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ||
核心 | 0 | 1 | 2 | 3 | ||||||
插座 | 0 | 1 | ||||||||
NUMA 节点 | 0 | 1 |
主机和虚拟机组合拓扑
vCPU 线程 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ||||||
主机 CPU 线程 | 0 | 3 | 1 | 4 | 2 | 5 | 6 | 9 | 7 | 10 | 8 | 11 | ||
核心 | 0 | 1 | 2 | 3 | 4 | 5 | ||||||||
插座 | 0 | 1 | ||||||||||||
NUMA 节点 | 0 | 1 |
在此方案中,有 2 个 NUMA 节点和 8 个 vCPU。因此,应将 4 个 vCPU 线程固定到每个节点。
此外,Red Hat 建议在每个节点上至少留出一个 CPU 线程用于主机系统操作。
因为在此示例中,每个 NUMA 节点都有 3 个核心,每个核心有 2 个主机 CPU 线程,所以节点 0 的集转换如下:
<vcpupin vcpu='0' cpuset='1'/>
<vcpupin vcpu='1' cpuset='4'/>
<vcpupin vcpu='2' cpuset='2'/>
<vcpupin vcpu='3' cpuset='5'/>
1.5 管理内核同页合并(KSM)
内核同页合并 (KSM) 通过在虚拟机 (VM) 之间共享相同的内存页来提高内存密度。但是,启用 KSM 会增加 CPU 利用率,并且可能会对整体性能产生不利影响,具体取决于工作负载。
根据您的要求,您可以为单个会话启用或禁用 KSM,也可以永久启用或禁用 KSM。
注意
在 RHEL 9 及更高版本中,KSM 默认处于禁用状态。
先决条件
- 对主机系统的 root 访问权限。
程序
-
禁用 KSM:
-
要停用单个会话的 KSM,请使用systemctl实用程序停止ksm和ksmtuned服务。
-
# systemctl stop ksm
# systemctl stop ksmtuned
要永久停用 KSM,请使用systemctl实用程序禁用 ksm和ksmtuned服务。
# systemctl disable ksm
Removed /etc/systemd/system/multi-user.target.wants/ksm.service.
# systemctl disable ksmtuned
Removed /etc/systemd/system/multi-user.target.wants/ksmtuned.service.
注意
在停用 KSM 之前,VM 之间共享的内存页将保持共享状态。若要停止共享,请使用以下命令删除PageKSM系统中的所有页面:
echo 2 > /sys/kernel/mm/ksm/run
匿名页面替换 KSM 页面后,khugepaged内核服务将在 VM 的物理内存上重建透明的大页面。
- 启用 KSM:
警告
启用 KSM 会增加 CPU 利用率并影响整体 CPU 性能。
1、安装服务:ksmtuned
# dnf install ksmtuned
2、启动服务:
-
要为单个会话启用 KSM,请使用
systemctl
实用程序启动ksm
和 ksmtuned
服务。
# systemctl start ksm
# systemctl start ksmtuned
要永久启用 KSM,请使用systemctl
实用程序启用ksm
和ksmtuned
服务。
# systemctl enable ksm
Created symlink /etc/systemd/system/multi-user.target.wants/ksm.service
/usr/lib/systemd/system/ksm.service
# systemctl enable ksmtuned
Created symlink /etc/systemd/system/multi-user.target.wants/ksmtuned.service
/usr/lib/systemd/system/ksmtuned.service