17.5. 优化虚拟机 CPU 性能
与主机中的物理 CPU 非常相似,vCPU 对虚拟机(VM)性能至关重要。因此,优化 vCPU 会对虚拟机的资源效率产生重大影响。优化 vCPU:
- 调整分配给虚拟机的主机 CPU 数。您可以使用 CLI 或 Web 控制台进行此操作。
确保 vCPU 模型与主机的 CPU 型号一致。例如,将 testguest1 虚拟机设置为使用主机的 CPU 型号:
# virt-xml testguest1 --edit --cpu host-model
- 停止内核同页合并(KSM) 。
如果您的主机使用非统一内存访问(NUMA),您也可以为其虚拟机 配置 NUMA。这会尽可能将主机的 CPU 和内存进程映射到虚拟机的 CPU 和内存进程上。实际上,NUMA 调优为 vCPU 提供了对分配给虚拟机的系统内存更精简的访问,这可以提高 vCPU 的处理效率。
详情请参阅 在虚拟机中配置 NUMA 和 vCPU 性能调整场景示例 。
17.5.1. 使用命令行界面添加和删除虚拟 CPU
要提高或优化虚拟机(VM)的 CPU 性能,您可以添加或删除分配给虚拟机的虚拟 CPU(vCPU)。
当在运行的虚拟机上执行时,这也被称为 vCPU 热插和热拔。但请注意,RHEL 8 不支持 vCPU 热拔,红帽不建议使用它。
先决条件
可选:查看目标虚拟机中的 vCPU 的当前状态。例如,显示 testguest 虚拟机上的 vCPU 数量:
# virsh vcpucount testguest maximum config 4 maximum live 2 current config 2 current live 1
此输出显示 testguest 目前使用 1 个 vCPU,另外 1 个 vCPu 可以热插入以提高虚拟机性能。但是,重新引导后,vCPU testguest 使用的数量会改为 2,而且能够热插 2 个 vCPU。
流程
调整可以附加到虚拟机的最大 vCPU 数量,其在虚拟机下次启动时生效。
例如,要将 testguest 虚拟机的最大 vCPU 数量增加到 8:
# virsh setvcpus testguest 8 --maximum --config
请注意,最大值可能会受 CPU 拓扑、主机硬件、hypervisor 和其他因素的限制。
将当前附加到虚拟机的 vCPU 数量调整到上一步中配置的最大值。例如:
将附加到正在运行的 testguest 虚拟机的 vCPU 数量增加到 4:
# virsh setvcpus testguest 4 --live
这会增加虚拟机的性能和主机的 testguest 负载占用,直到虚拟机下次引导为止。
将附加到 testguest 虚拟机的 vCPU 数量永久减少至 1:
# virsh setvcpus testguest 1 --config
这会降低虚拟机的性能和 testguest 的主机负载占用。但是,如果需要可热插入虚拟机以暂时提高性能。
验证
确认虚拟机的 vCPU 的当前状态反映了您的更改。
# virsh vcpucount testguest maximum config 8 maximum live 4 current config 1 current live 4
其它资源
17.5.2. 使用 Web 控制台管理虚拟 CPU
通过使用 RHEL 8 web 控制台,您可以查看并配置 web 控制台连接的虚拟机使用的虚拟 CPU。
先决条件
已安装 RHEL 8 web 控制台。
具体步骤请参阅安装并启用 Web 控制台。
- Web 控制台 VM 插件 已安装在您的系统上。
流程
登录到 RHEL 8 web 控制台。
详情请参阅 登录到 web 控制台。
在
界面中,点击您要查看其信息的虚拟机。此时将打开一个新页面,其中包含关于所选虚拟机基本信息的概述部分,以及用于访问虚拟机的图形界面的控制台部分。
单击概述窗格中 vCPU 数旁边的
。此时会出现 vCPU 详情对话框。
为所选虚拟机配置虚拟 CPU。
vCPU 数量 - 当前正在使用的 vCPU 数量。
注意vCPU 数量不能超过 vCPU 的最大值。
- vCPU 最大 - 可为虚拟机配置的最大虚拟 CPU 数。如果这个值大于 vCPU Count,可以为虚拟机附加额外的 vCPU。
- 插槽 - 向虚拟机公开的插槽数量。
- 每个插槽的内核数 - 向虚拟机公开的每个插槽的内核数。
每个内核的线程数 - 向虚拟机公开的每个内核的线程数。
请注意, 插槽、每个插槽的内核数和每个内核的线程数选项调整了虚拟机的 CPU 拓扑。这可能对 vCPU 性能有好处,但可能会影响客户机操作系统中某些软件的功能。如果您的部署不需要不同的设置,请保留默认值。
点
。配置了虚拟机的虚拟 CPU。
注意对虚拟 CPU 设置的更改仅在重启虚拟机后生效。
其它资源
17.5.3. 在虚拟机中配置 NUMA
以下方法可用于配置 RHEL 8 主机上虚拟机(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 兼容。
流程
为便于使用,您可以使用自动化实用程序和服务设置虚拟机的 NUMA 配置。但是,手动 NUMA 设置可能会显著提高性能。
自动方法
将虚拟机的 NUMA 策略设为
Preferred
。例如,对于 testguest5 虚拟机要这样做:# 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
手动方法
将特定 vCPU 线程固定到特定主机 CPU 或者 CPU 范围。在非 NUMA 主机和虚拟机上也可以这样做,我们推荐您使用一种安全的方法来提高 vCPU 性能。
例如,以下命令将 testguest6 虚拟机的 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
固定 vCPU 线程后,您还可以将与指定虚拟机关联的 QEMU 进程线程固定到特定的主机 CPU 或 CPU 范围。例如:以下命令将 testguest6 的 QEMU 进程线程 固定到 CPU 13 和 15,确认成功:
# virsh emulatorpin testguest6 13,15 # virsh emulatorpin testguest6 emulator: CPU Affinity ---------------------------------- *: 13,15
最后,您也可以指定将哪些主机 NUMA 节点专门分配给某个虚拟机。这可提高虚拟机 vCPU 的主机内存用量。例如,以下命令将 testguest6 设置为使用主机 NUMA 节点 3 到 5,确认成功:
# virsh numatune testguest6 --nodeset 3-5 # virsh numatune testguest6
为了获得最佳性能,建议使用以上列出的所有手动调优方法
其它资源
- vCPU 性能调整场景示例
-
使用
numastat
工具 查看系统的当前 NUMA 配置
17.5.4. vCPU 性能调整场景示例
要获得最佳 vCPU 性能,红帽建议将手动 vcpupin
、emulatorpin
和 numatune
设置一起使用,例如在以下场景中。
起始场景
您的主机有以下与硬件相关的信息:
- 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
您打算将现有的虚拟机修改为有 8 个 vCPU,这意味着单个 NUMA 节点无法容纳它。
因此,您应该在每个 NUMA 节点上分发 4 个 vCPU,并使 vCPU 拓扑尽可能接近主机拓扑。这意味着,作为给定物理 CPU 的同级线程运行的 vCPU 应该固定到同一核上的主机线程。详情请查看以下解决方案:
解决方案
获取有关主机拓扑的信息:
# 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>
- 可选: 使用适用的工具和实用程序 测试虚拟机的性能。
在主机上设置并挂载 1 GiB 巨页:
注意1 GiB 巨页可能不适用于某些架构和配置,如 ARM 64 主机。
在主机的内核命令行中添加以下行:
default_hugepagesz=1G hugepagesz=1G
使用以下内容创建
/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
使用以下内容创建
/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 巨页。
使在上一步中创建的脚本可执行:
# chmod +x /etc/systemd/hugetlb-reserve-pages.sh
在引导时启用巨页保留:
# systemctl enable hugetlb-gigantic-pages
使用
virsh edit
命令编辑您要优化的虚拟机的 XML 配置,在本例中为 super-VM :# virsh edit super-vm
用以下方法调整虚拟机的 XML 配置:
-
将虚拟机设置为使用 8 个静态 vCPU。使用
<vcpu/>
元素来执行此操作。 将每个 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>
将虚拟机设置为使用 1 GiB 巨页:
<memoryBacking> <hugepages> <page size='1' unit='GiB'/> </hugepages> </memoryBacking>
配置虚拟机的 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"/>
-
将虚拟机设置为使用 8 个静态 vCPU。使用
确认生成的虚拟机 XML 配置包含类似如下内容:
[...] <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>
- 可选: 使用 适用的工具和实用程序 来评估虚拟机优化的影响,以测试虚拟机的性能。
拓扑示例
下表演示了 vCPU 和主机 CPU 之间的连接:
表 17.1. 主机拓扑 CPU 线程
0
3
1
4
2
5
6
9
7
10
8
11
内核
0
1
2
3
4
5
插槽
0
1
NUMA 节点
0
1
表 17.2. VM 拓扑 vCPU 线程
0
1
2
3
4
5
6
7
内核
0
1
2
3
插槽
0
1
NUMA 节点
0
1
表 17.3. 合并主机和虚拟机拓扑 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 线程。
另外,红帽建议在每个节点上至少保留一个 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'/>
17.5.5. 停止内核相同页面合并
虽然内核相同页面合并(KSM)提高了内存密度,但它会增加 CPU 的使用率,并且可能会对总体性能产生不利影响,具体取决于工作负载。在这种情况下,您可以通过停用 KSM 来提高虚拟机(VM)的性能。
根据您的要求,您可以对单个会话停用 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 前在虚拟机间共享的内存页将保持共享。要停止共享,请使用以下命令删除系统中的所有 PageKSM
页面:
# echo 2 > /sys/kernel/mm/ksm/run
匿名页面替换了 KSM 页面后,khugepaged
内核服务将在虚拟机物理内存中重建透明的大页面。