Red Hat Training

A Red Hat training course is available for RHEL 8

第 14 章 优化虚拟机性能

与主机相比,虚拟机的性能总会有所降低。以下小节解释了导致这个问题的原因,并提供了有关如何在 RHEL 8 中最小化虚拟化性能影响的说明,以便您的硬件基础架构资源能尽可能高效地使用。

14.1. 影响虚拟机性能的因素

虚拟机作为用户空间进程在主机上运行。因此管理程序需要转换主机的系统资源,以便虚拟机可使用它们。因此,部分资源会被转换消耗,因此虚拟机无法获得与主机相同的性能效率。

虚拟化对系统性能的影响

体虚拟机性能损失的原因包括:

  • 虚拟 CPU(vCPU)是主机上的线,,由 Linux 调度程序处理。
  • VM 不会自动继承主机内核的优化功能,比如 NUMA 或巨页。
  • 主机的磁盘和网络 I/O 设置可能会对虚拟机有显著的性能影响。
  • 网络流量通常通过基于软件的网桥到达虚拟机。
  • 根据主机设备及其模型,模拟特定硬件可能会产生大量开销。

虚拟化对虚拟机性能的影响严重程度受到各种因素的影响,具体包括:

  • 并行运行的虚拟机数量。
  • 每个虚拟机使用的虚拟设备数量。
  • 虚拟机使用的设备类型。

降低虚拟机性能损失

RHEL 8 提供很多功能,可用于降低虚拟化的负面影响。值得注意的是:

重要

调整虚拟机性能会对其他虚拟化功能造成负面影响。例如,它可以使迁移修改过的虚拟机更为困难。

14.2. 使用 tuned 优化虚拟机性能

tuned 工具是一种调优配置集交付机制,可根据特定工作负载特性进行调整,如 CPU 密集型任务的要求或存储网络吞吐量响应能力。它提供很多预先配置的调优配置文件,以便在多个特定用例中增强性能并降低功耗。您可以编辑这些配置集,或创建新配置集来创建适合您的环境的性能解决方案,包括虚拟环境。

红帽建议在 RHEL 8 中使用以下配置集:

  • 对于 RHEL 8 虚拟机,使用 virtual-guest 配置集。它基于 throughput-performance 配置集,但也会降低虚拟内存的交换性。
  • 对于 RHEL 8 虚拟化主机,请使用 virtual-host 配置集。这可提高脏内存页面的主动回写,这有助于主机性能。

先决条件

流程

启用特定的 tuned 配置集:

  1. 列出可用的 tuned 配置集。

    # tuned-adm list
    
    Available profiles:
    - balanced             - General non-specialized tuned profile
    - desktop              - Optimize for the desktop use-case
    [...]
    - virtual-guest        - Optimize for running inside a virtual guest
    - virtual-host         - Optimize for running KVM guests
    Current active profile: balanced
  2. 可选: 创建新 tuned 配置集或编辑现有的 tuned 配置集。

    如需更多信息,请参阅自定义 tuned 配置集

  3. 激活 tuned 配置集。

    # tuned-adm profile selected-profile
    • 要优化虚拟化主机,请使用 virtual-host 配置集。

      # tuned-adm profile virtual-host
    • 在 RHEL 虚拟机操作系统中,使用 virtual-guest 配置集。

      # tuned-adm profile virtual-guest

其它资源

14.3. 配置虚拟机内存

要提高虚拟机(VM)的性能,您可以为虚拟机分配额外的主机 RAM。类似地,您可以减少分配给虚拟机的内存量,从而使主机内存可以分配给其他虚拟机或任务。

要执行这些操作,您可以使用 Web 控制台或 命令行界面

14.3.1. 使用 web 控制台添加和删除虚拟机内存

要提高虚拟机(VM)的性能或释放它使用的主机资源,您可以使用 Web 控制台调整分配给虚拟机的内存量。

先决条件

  • 客户端操作系统正在运行内存 balloon 驱动程序。请执行以下命令校验:

    1. 确定虚拟机的配置包含 memballoon 设备:

      # virsh dumpxml testguest | grep memballoon
      <memballoon model='virtio'>
          </memballoon>

      如果这个命令显示了输出结果,且模型没有设置为 none,则代表 memballoon 设备存在。

    2. 确定 ballon 驱动程序正在客户端操作系统中运行。

  • 要使用 Web 控制台管理虚拟机,请安装 Web 控制台虚拟机插件

流程

  1. 可选:包含有关虚拟机最大内存和当前使用的内存的信息。这将作为您更改的基准,并进行验证。

    # virsh dominfo testguest
    Max memory:     2097152 KiB
    Used memory:    2097152 KiB
  2. 虚拟机接口中,点包含您要查看和调整分配的内存的虚拟机名称的一行。

    行会展开,以显示 Overview 窗格中有关所选虚拟机的基本信息。

  3. 点击 Overview 窗格中的 Memory 行值。

    此时会出现 Memory Adjustment 对话框。

    virt 内存 cockpit
  4. 为所选虚拟机配置虚拟 CPU。

    • 最大分配 - 设置虚拟机可用于其进程的最大主机内存量。增加这个值可以提高虚拟机的性能风险,降低这个值会降低虚拟机在主机上的性能占用空间。

      只有在关闭虚拟机上才能调整最大内存分配。

    • 当前分配 - 设置分配给虚拟机的实际内存量。您可以调整值,以规范虚拟机为其进程可用的内存。这个值不能超过最大分配值。
  5. Save

    调整了虚拟机的内存分配。

其它资源

14.3.2. 使用命令行界面添加和删除虚拟机内存

若要提高虚拟机(VM)的性能或释放其使用的主机资源,您可以使用 CLI 调整分配给虚拟机的内存量。

先决条件

  • 客户端操作系统正在运行内存 balloon 驱动程序。请执行以下命令校验:

    1. 确定虚拟机的配置包含 memballoon 设备:

      # virsh dumpxml testguest | grep memballoon
      <memballoon model='virtio'>
          </memballoon>

      如果这个命令显示了输出结果,且模型没有设置为 none,则代表 memballoon 设备存在。

    2. 确定 ballon 驱动程序正在客户端操作系统中运行。

流程

  1. 可选:包含有关虚拟机最大内存和当前使用的内存的信息。这将作为您更改的基准,并进行验证。

    # virsh dominfo testguest
    Max memory:     2097152 KiB
    Used memory:    2097152 KiB
  2. 调整分配给虚拟机的最大内存。增加这个值可以提高虚拟机的性能风险,降低这个值会降低虚拟机在主机上的性能占用空间。请注意,此更改只能在关闭虚拟机上执行,因此调整正在运行的虚拟机需要重新引导才能生效。

    例如,将 testguest 虚拟机可以使用的最大内存更改为 4096 MiB:

    # virt-xml testguest --edit --memory memory=4096,currentMemory=4096
    Domain 'testguest' defined successfully.
    Changes will take effect after the domain is fully powered off.
  1. 可选: 您还可以调整虚拟机当前使用的内存,最多不超过最大分配数。这限制了虚拟机在主机上的内存负载,直到下一次重启为止,而不更改虚拟机的最大分配。

    # virsh setmem testguest --current 2048

验证

  1. 确认虚拟机使用的内存已更新:

    # virsh dominfo testguest
    Max memory:     4194304 KiB
    Used memory:    2097152 KiB
  2. 可选:如果您调整了当前虚拟机内存,您可以获取虚拟机的内存 balloon 统计,以评估它如何有效地控制其内存使用量。

     # virsh domstats --balloon testguest
    Domain: 'testguest'
      balloon.current=365624
      balloon.maximum=4194304
      balloon.swap_in=0
      balloon.swap_out=0
      balloon.major_fault=306
      balloon.minor_fault=156117
      balloon.unused=3834448
      balloon.available=4035008
      balloon.usable=3746340
      balloon.last-update=1587971682
      balloon.disk_caches=75444
      balloon.hugetlb_pgalloc=0
      balloon.hugetlb_pgfail=0
      balloon.rss=1005456

其它资源

14.3.3. 其它资源

  • 要增加正在运行的虚拟机的最大内存,您可以将内存设备附加到虚拟机。这也被称为内存热插拔。详情请查看 将设备附加到虚拟机

    请注意,在 RHEL 8 中不支持从虚拟机中删除内存设备,也称为内存热拔。红帽强烈建议不要使用它。

14.4. 优化虚拟机 I/O 性能

虚拟机(VM)的输入和输出(I/O)功能可能会显著限制虚拟机的整体效率。要解决这个问题,您可以通过配置块 I/O 参数来优化虚拟机的 I/O。

14.4.1. 在虚拟机中调整块 I/O

当一个或多个虚拟机正在使用多个块设备时,可能需要通过修改虚拟设备的 I/O 优先级来调整虚拟设备的 I/O 权重

增加设备的 I/O 权重会增加设备的 I/O 带宽的优先级,从而为它提供更多主机资源。同样的,降低设备的权重可使其消耗较少的主机资源。

注意

每个设备的 weight 值都必须在 1001000 范围内。或者,该值可以是 0,它从每个设备列表中删除该设备。

流程

显示和设置虚拟机的块 I/O 参数:

  1. 显示虚拟机的当前 <blkio> 参数:

    # virsh dumpxml VM-name

    <domain>
      [...]
      <blkiotune>
        <weight>800</weight>
        <device>
          <path>/dev/sda</path>
          <weight>1000</weight>
        </device>
        <device>
          <path>/dev/sdb</path>
          <weight>500</weight>
        </device>
      </blkiotune>
      [...]
    </domain>
  2. 编辑指定设备的 I/O 加权:

    # virsh blkiotune VM-name --device-weights device, I/O-weight

    例如:以下将 liftrul 虚拟机中的 /dev/sda 设备的权重改为 500。

    # virsh blkiotune liftbrul --device-weights /dev/sda, 500

14.4.2. 虚拟机中的磁盘 I/O 节流

当多个虚拟机同时运行时,它们可能会通过使用过量磁盘 I/O 来干扰系统性能。KVM 虚拟化中的磁盘 I/O 节流使得能够对从虚拟机发送至主机的磁盘 I/O 请求设定限制。这可以防止虚拟机过度利用共享资源并影响其他虚拟机的性能。

要启用磁盘 I/O 节流,请对从附加到虚拟机到主机计算机的每个块设备发送的磁盘 I/O 请求设置限制。

流程

  1. 使用 virsh domblklist 命令列出指定虚拟机中的所有磁盘设备名称。

    # virsh domblklist rollin-coal
    Target     Source
    ------------------------------------------------
    vda        /var/lib/libvirt/images/rollin-coal.qcow2
    sda        -
    sdb        /home/horridly-demanding-processes.iso
  2. 找到您要节流的虚拟磁盘挂载的主机块设备。

    例如:如果要从上一步中节流 sdb 虚拟磁盘,以下输出显示磁盘被挂载到 /dev/nvme0n1p3 分区中。

    $ lsblk
    NAME                                          MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
    zram0                                         252:0    0     4G  0 disk  [SWAP]
    nvme0n1                                       259:0    0 238.5G  0 disk
    ├─nvme0n1p1                                   259:1    0   600M  0 part  /boot/efi
    ├─nvme0n1p2                                   259:2    0     1G  0 part  /boot
    └─nvme0n1p3                                   259:3    0 236.9G  0 part
      └─luks-a1123911-6f37-463c-b4eb-fxzy1ac12fea 253:0    0 236.9G  0 crypt /home
  3. 使用 virsh blkiotune 命令为块设备设置 I/O 限值。

    # virsh blkiotune VM-name --parameter device,limit

    以下示例将 rollin-coal 虚拟机上的 sdb 磁盘限制为每秒 1000 个读写 I/O 操作,每秒读写 I/O 操作吞吐量 50 MB。

    # virsh blkiotune rollin-coal --device-read-iops-sec /dev/nvme0n1p3,1000 --device-write-iops-sec /dev/nvme0n1p3,1000 --device-write-bytes-sec /dev/nvme0n1p3,52428800 --device-read-bytes-sec /dev/nvme0n1p3,52428800

附加信息

  • 磁盘 I/O 节流可用于各种情况,例如,属于不同客户的虚拟机在同一主机上运行,或者为不同的虚拟机提供服务质量保障时。磁盘 I/O 节流还可用来模拟较慢的磁盘。
  • I/O 节流可以独立于附加到虚拟机的每个块设备应用,并支持吞吐量和 I/O 操作的限制。
  • 红帽不支持使用 virsh blkdeviotune 命令在虚拟机中配置 I/O 节流。有关使用 RHEL 8 作为虚拟机主机时不支持的功能的更多信息,请参阅 RHEL 8 虚拟化中的不受支持的功能

14.4.3. 启用多队列 virtio-scsi

当在虚拟机(VM)中使用 virtio-scsi 存储设备时,多队列 virtio-scsi 功能可提高存储性能和可扩展性。它允许每个虚拟 CPU(vCPU)拥有单独的队列和中断,而不影响其他 vCPU。

流程

  • 要为特定虚拟机启用多队列 virtio-scsi 支持,请在虚拟机的 XML 配置中添加以下内容,其中 N 是 vCPU 队列的总数:

    <controller type='scsi' index='0' model='virtio-scsi'>
       <driver queues='N' />
    </controller>

14.5. 优化虚拟机 CPU 性能

与主机计算机中的物理 CPU 非常相似,vCPU 对虚拟机(VM)性能至关重要。因此,优化 vCPU 会对虚拟机的资源效率产生重大影响。优化 vCPU:

  1. 调整分配给虚拟机的主机 CPU 数。您可以使用 CLIWeb 控制台进行此操作。
  2. 确保 vCPU 模型与主机的 CPU 型号一致。例如,将 testguest1 虚拟机设置为使用主机的 CPU 型号:

    # virt-xml testguest1 --edit --cpu host-model
  3. 取消激活内核同页合并(KSM)。
  4. 如果您的主机使用非统一内存访问 (NUMA),您也可以为其虚拟机配置 NUMA。这会尽可能将主机的 CPU 和内存进程映射到虚拟机的 CPU 和内存进程上。实际上,NUMA 调优为 vCPU 提供了对分配给虚拟机的系统内存的更精简访问,这可以提高 vCPU 处理效率。

    详情请查看 第 14.5.3 节 “在虚拟机中配置 NUMA”第 14.5.4 节 “vCPU 性能调整场景示例”

14.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。

流程

  1. 调整可以附加到虚拟机的最大 vCPU 数量,这在虚拟机下次引导时生效。

    例如,要将 testguest 虚拟机的最大 vCPU 数量增加到 8:

    # virsh setvcpus testguest 8 --maximum --config

    请注意,最大值可能受 CPU 拓扑、主机硬件、系统管理程序和其他因素的限制。

  2. 将当前附加到虚拟机的 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

其它资源

14.5.2. 使用 Web 控制台管理虚拟 CPU

使用 RHEL 8 web 控制台,您可以查看并配置 web 控制台连接的虚拟机使用的虚拟 CPU。

流程

  1. Virtual Machines 界面中,单击带有您要查看和配置虚拟 CPU 参数的虚拟机名称的行。

    行扩展以显示 Overview 窗格,其中包含有关所选虚拟机的基本信息,包括虚拟 CPU 数量,以及用于关闭和删除虚拟机的控件。

  2. 点击 Overview 窗格中的 vCPU 数量。

    此时会出现 vCPU 详情对话框。

    Cockpit 配置 vCPU
    注意

    只有在更改虚拟 CPU 设置后,vCPU 详情对话框中的警告会出现。

  3. 为所选虚拟机配置虚拟 CPU。

    • vCPU 数量 - 当前正在使用的 vCPU 数量。

      注意

      vCPU 数量不能超过 vCPU 的最大值。

    • vCPU 最大 - 可为虚拟机配置的最大虚拟 CPU 数。如果这个值大于 vCPU Count,可以为虚拟机附加额外的 vCPU。
    • 插槽 - 向虚拟机公开的插槽数量。
    • 每个插槽的内核数 - 向虚拟机公开的每个插槽的内核数。
    • 每个内核的线程数 - 向虚拟机公开的每个内核的线程数。

      请注意, 插槽每个插槽的内核数每个内核的线程数选项调整了虚拟机的 CPU 拓扑。这可能对 vCPU 性能有用,可能会影响客户机操作系统中某些软件的功能。如果您的部署不需要不同的设置,红帽建议保留默认值。

  4. 应用

    配置了虚拟机的虚拟 CPU。

    注意

    对虚拟 CPU 设置的更改仅在重启虚拟机后生效。

其他资源:

14.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 命令自动将虚拟机 CPU 与内存资源匹配。

    # numad

手动方法

  1. 将特定 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
  2. 固定 vCPU 线程后,您还可以将与指定虚拟机关联的 QEMU 进程线程固定到特定的主机 CPU 或 CPU 范围。例如:以下命令将 testguest6 的 QEMU 进程线程 固定到 CPU 13 和 15,确认成功:

    # virsh emulatorpin testguest6 13,15
    # virsh emulatorpin testguest6
    emulator: CPU Affinity
    ----------------------------------
           *: 13,15
  3. 最后,您也可以指定将哪些主机 NUMA 节点专门分配给特定的虚拟机。这可提高虚拟机 vCPU 的主机内存用量。例如,以下命令将 testguest6 设置为使用主机 NUMA 节点 3 到 5,确认成功:

    # virsh numatune testguest6 --nodeset 3-5
    # virsh numatune testguest6

其它资源

14.5.4. vCPU 性能调整场景示例

要获得最佳 vCPU 性能,红帽建议您手动 vcpupinemulatorpinnumatune 设置,如以下场景中所示。

起始场景

  • 您的主机有以下与硬件相关的信息:

    • 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 应该固定到同一内核中的主机线程。详情请查看以下解决方案:

解决方案

  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. 可选:使用 ??? 适用的工具和实用程序测试虚拟机的性能
  3. 在主机上设置并挂载 1 GiB 巨页:

    1. 在主机的内核命令行中添加以下行:

      default_hugepagesz=1G hugepagesz=1G
    2. 使用以下内容创建 /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
    3. 使用以下内容创建 /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 巨页。

    4. 使在上一步中创建的脚本可执行:

      # chmod +x /etc/systemd/hugetlb-reserve-pages.sh
    5. 在引导时启用巨页保留:

      # systemctl enable hugetlb-gigantic-pages
  4. 使用 virsh edit 命令编辑您要优化的虚拟机的 XML 配置,在这个示例中 super-VM

    # virsh edit super-vm
  5. 用以下方法调整虚拟机的 XML 配置:

    1. 将虚拟机设置为使用 8 个静态 vCPU。使用 <vcpu/> 项进行此操作。
    2. 将每个 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>
    3. 将虚拟机设置为使用 1 GiB 巨页:

      <memoryBacking>
        <hugepages>
          <page size='1' unit='GiB'/>
        </hugepages>
      </memoryBacking>
    4. 配置虚拟机的 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>
    5. 确保 CPU 模式被设置为 host-passthrough,且 CPU 在 passthrough 模式中使用缓存:

      <cpu mode="host-passthrough">
        <topology sockets="2" cores="2" threads="2"/>
        <cache mode="passthrough"/>
  6. 虚拟机的 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>
  7. 可选:使用 ??? 适用的工具和实用程序测试虚拟机的性能,以评估虚拟机优化的影响。

其它资源

  • 下表演示了 vCPU 和主机 CPU 之间的连接:

    表 14.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

    表 14.2. VM 拓扑

    vCPU 线程

    0

    1

    2

    3

    4

    5

    6

    7

    内核

    0

    1

    2

    3

    插槽

    0

    1

    NUMA 节点

    0

    1

    表 14.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'/>

14.5.5. 取消激活内核相同页面合并

虽然内核相同页面合并(KSM)提高了内存密度,但它会增加 CPU 利用率,并且可能会根据工作负载对整体性能造成负面影响。在这种情况下,您可以通过停用 KSM 来提高虚拟机(VM)性能。

根据您的要求,可以为单个会话取消激活 KSM,也可以永久停用。

流程

  • 要在一个会话中取消激活 KSM,请使用 systemctl 工具停止 ksmksmtuned 服务。

    # systemctl stop ksm
    
    # systemctl stop ksmtuned
  • 要永久取消激活 KSM,使用 systemctl 工具禁用 ksmksmtuned 服务。

    # 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 内核服务将在虚拟机物理内存上重建透明巨页。

14.6. 优化虚拟机网络性能

由于虚拟机的网络接口卡(NIC)的虚拟性质,虚拟机会丢失其分配的主机网络带宽的一部分,这样可以降低虚拟机的整体工作负载效率。以下提示可最大程度降低虚拟化对虚拟 NIC(vNIC)吞吐量的负面影响。

流程

使用以下任一方法并观察它是否对虚拟机网络性能有帮助:

启用 vhost_net 模块

在主机上,确定启用了 vhost_net 内核功能:

# lsmod | grep vhost
vhost_net              32768  1
vhost                  53248  1 vhost_net
tap                    24576  1 vhost_net
tun                    57344  6 vhost_net

如果这个命令的输出为空白,启用 vhost_net 内核模块:

# modprobe vhost_net
设置多队列 virtio-net

要为虚拟机设置 多队列 virtio-net 功能,使用 virsh edit 命令编辑虚拟机的 XML 配置。在 XML 中,将以下内容添加到 <devices> 部分,并使用虚拟机中的 vCPU 数量替换 N,最多为 16:

<interface type='network'>
      <source network='default'/>
      <model type='virtio'/>
      <driver name='vhost' queues='N'/>
</interface>

如果虚拟机正在运行,重启它以使更改生效。

批量网络数据包

在具有长传输路径的 Linux VM 配置中,在将数据包提交到内核之前进行批处理可以提高缓存利用率。要设置数据包批处理,请在主机上使用以下命令,并将 tap0 替换为虚拟机使用的网络接口名称:

# ethtool -C tap0 rx-frames 128
SR-IOV
如果您的主机 NIC 支持 SR-IOV,请为您的 vNIC 使用 SR-IOV 设备分配。如需更多信息,请参阅管理 SR-IOV 设备

14.7. 虚拟机性能监控工具

要确定哪些消耗了最多 VM 资源以及虚拟机性能需要优化的哪一方面,可以使用一般诊断工具和特定于虚拟机的工具。

默认操作系统性能监控工具

要进行标准性能评估,您可以使用主机和客户机操作系统默认提供的工具:

  • 在 RHEL 8 主机上,以 root 用户身份使用 top 实用程序或 系统监控应用程序,并在输出中查找 qemuvirt。这显示了您的虚拟机消耗的主机系统资源量。

    • 如果监控工具显示任何 qemuvirt 进程消耗大量主机 CPU 或内存容量,请使用 perf 工具程序进行调查。详情请查看以下信息。
    • 另外,如果名为 examplevhost_net-1234vhost_net 线程进程显示为消耗过多的主机 CPU 容量,请考虑使用虚拟网络优化功能,如 multi-queue virtio-net
  • 在客户机操作系统上,使用系统上可用的性能实用程序和应用程序来评估哪些进程消耗最多的系统资源。

    • 在 Linux 系统中,您可以使用 top 工具。
    • 在 Windows 系统中,您可以使用 Task Manager 应用程序。

perf kvm

您可以使用 perf 实用程序收集有关 RHEL 8 主机性能的特定虚拟化统计。要做到这一点:

  1. 在主机上安装 perf 软件包:

    # yum install perf
  2. 使用 perf kvm stat 命令之一显示虚拟化主机的 perf 统计:

    • 对于虚拟机监控程序的实时监控,请使用 perf kvm stat live 命令。
    • 要记录虚拟机监控程序的 perf 数据,请使用 perf kvm stat record 命令激活日志。取消或中断命令后,数据保存在 perf.data.guest 文件中,该文件可使用 perf kvm stat report 命令分析。
  3. 分析 VM-EXIT 事件类型及其分布的 perf 输出。例如,PAUSE_INSTRUCTION 事件应该不频繁,但在以下输出中,此事件的频繁发生意味着主机 CPU 没有正确处理正在运行的 vCPU。在这种情况下,请考虑关闭部分活动虚拟机,从这些虚拟机中删除 vCPU,或调优 vCPU 的性能

    # perf kvm stat report
    
    Analyze events for all VMs, all VCPUs:
    
    
                 VM-EXIT    Samples  Samples%     Time%    Min Time    Max Time         Avg time
    
      EXTERNAL_INTERRUPT     365634    31.59%    18.04%      0.42us  58780.59us    204.08us ( +-   0.99% )
               MSR_WRITE     293428    25.35%     0.13%      0.59us  17873.02us      1.80us ( +-   4.63% )
        PREEMPTION_TIMER     276162    23.86%     0.23%      0.51us  21396.03us      3.38us ( +-   5.19% )
       PAUSE_INSTRUCTION     189375    16.36%    11.75%      0.72us  29655.25us    256.77us ( +-   0.70% )
                     HLT      20440     1.77%    69.83%      0.62us  79319.41us  14134.56us ( +-   0.79% )
                  VMCALL      12426     1.07%     0.03%      1.02us   5416.25us      8.77us ( +-   7.36% )
           EXCEPTION_NMI         27     0.00%     0.00%      0.69us      1.34us      0.98us ( +-   3.50% )
           EPT_MISCONFIG          5     0.00%     0.00%      5.15us     10.85us      7.88us ( +-  11.67% )
    
    Total Samples:1157497, Total events handled time:413728274.66us.

    perf kvm stat 输出中可能会信号问题的其他事件类型包括:

有关使用 perf 监控虚拟化性能的详情请参考 perf-kvm man page。

numastat

要查看系统的当前 NUMA 配置,您可以使用 numastat 工具程序,通过安装 numactl 软件包来提供该工具。

以下显示了一个有 4 个运行虚拟机的主机,各自从多个 NUMA 节点获取内存。这不是 vCPU 性能的最佳方案,并保证调整

# numastat -c qemu-kvm

Per-node process memory usage (in MBs)
PID              Node 0 Node 1 Node 2 Node 3 Node 4 Node 5 Node 6 Node 7 Total
---------------  ------ ------ ------ ------ ------ ------ ------ ------ -----
51722 (qemu-kvm)     68     16    357   6936      2      3    147    598  8128
51747 (qemu-kvm)    245     11      5     18   5172   2532      1     92  8076
53736 (qemu-kvm)     62    432   1661    506   4851    136     22    445  8116
53773 (qemu-kvm)   1393      3      1      2     12      0      0   6702  8114
---------------  ------ ------ ------ ------ ------ ------ ------ ------ -----
Total              1769    463   2024   7462  10037   2672    169   7837 32434

相反,以下显示单个节点为每个虚拟机提供内存,这效率显著提高。

# numastat -c qemu-kvm

Per-node process memory usage (in MBs)
PID              Node 0 Node 1 Node 2 Node 3 Node 4 Node 5 Node 6 Node 7 Total
---------------  ------ ------ ------ ------ ------ ------ ------ ------ -----
51747 (qemu-kvm)      0      0      7      0   8072      0      1      0  8080
53736 (qemu-kvm)      0      0      7      0      0      0   8113      0  8120
53773 (qemu-kvm)      0      0      7      0      0      0      1   8110  8118
59065 (qemu-kvm)      0      0   8050      0      0      0      0      0  8051
---------------  ------ ------ ------ ------ ------ ------ ------ ------ -----
Total                 0      0   8072      0   8072      0   8114   8110 32368