前言:PVE平台虚拟机调度策略

PVE (Proxmox Virtual Environment)是什么就不多介绍了,至少说现阶段在开源虚拟机平台尤其是超融合平台这一块,PVE还是无人能出其二。不过PVE在虚拟机设置方面还是有诸多遗憾,相比原生kvm+virsh管理反向阉割了诸多配置,比如绑定虚拟机CPU核心。而且官方明确表示没有在GUI加入cpu核心绑定相关设定。

而且全网搜索似乎没有中文相关的pve绑核操作,英文资料也只存在于论坛中,寥寥几句提到numa0 numa1 cpus,以及用taskset绑核。我就迷惑了,是大家都不屑于用多路系统还是从来不关心虚拟机NUMA Aware优化相关问题?或者就是这个是基本操作,默认都会设置了。。。

所以这里粗略总结了一下pve虚拟机对cpu和内存分布调度策略,以及打开numa选项后的运行逻辑。经验总结,不保证正确性,仅供讨论。

pve处理器设置中的Enable NUMA选项

以下总结根据PVE 7.1在双路系统中的表现而得出:

  1. 默认的cpu调度是:按照整个宿主机系统的CPU情况来均分给个虚拟机,也就是双路两组NUMA的CPU核心看作一个整体均匀分配,虚拟机CPU大于等于2时就会跑在多个NUMA上。如果NUMA0的CPU已经满载了(特指宿主机运行大量使用CPU的程序占满NUMA0),此时新启动的虚拟机会优先跑在另一个NUMA1上;即便是已经启动虚拟机,系统也会考虑因为numa1负载低而调配vcpu到numa1运行。但是如果负载来自虚拟机且没有绑核则不会出现这种情况,因为虚拟机vcpu会被跨numa分配到各个物理核心以达到均匀。
  2. 默认设置下不勾选Enable NUMA,虚拟机内存分配会优先分配一个NUMA的内存,占满后再分配另一个
  3. 选上Enable NUMA则是缺页中断产生在哪个cpu,对应NUMA的内存分配给虚拟机

所以如果不开Enable NUMA,对双路互联系统会带来极大的负担,跨Sockets通讯将会十分频繁,因为一半的核心跑在另一个NUMA,而内存大多数情况都分配在一个NUMA。

如果打开Enable NUMA,由于无法判断虚拟机内程序运行情况,可能大量的缺页中断产生在numa0的cpu,导致numa0的内存被大量消耗,而numa1内存过剩,此时如果再申请numa0的内存,会产生OOM(Out Of Memory)报错,进而导致虚拟机停止运行。这样一来宿主机的内存利率用就会变低,原因是虚拟机申请的是NUMA Aware的内存,可能导致不同NUMA节点内存使用量不平衡。

要解决上述问题,就只能绑定CPU和内存到一个NUMA。而前面又说了,官方不提供虚拟机绑定CPU核心的选项。所以本文基于这样的现实情况来解决PVE虚拟机核心绑定 cpu pinning的问题。

方法1:通过hookscript实现绑核

编辑绑定核心文件 /etc/pve/qemu-server/your_vmid.cpuset

(your_vmid替换成虚拟机对应的vmid)

0-11 # 代表绑定cpu0,cpu1,...,cpu11共12核

编辑文件taskset-hook.sh

#!/bin/bash

vmid="$1"
phase="$2"

if [[ "$phase" == "post-start" ]]; then
    main_pid="$(< /run/qemu-server/$vmid.pid)"

    #cpuset="0-11"
    cpuset="$(< /etc/pve/qemu-server/$vmid.cpuset)"

    taskset --cpu-list  --all-tasks --pid "$cpuset" "$main_pid"
fi

然后把脚本放到某个存储库(本位以local为例)的 snippets 中:

cp taskset-hook.sh /var/lib/vz/snippets
chmod +x  /var/lib/vz/snippets/taskset-hook.sh

最后对需要绑核的虚拟机VMID执行以下命令:

qm set VMID --hookscript local:snippets/taskset-hook.sh

如此虚拟机启动后进入post-start阶段时,PVE便会自动调用脚本通过taskset绑定对应vmid虚拟机跟物理机的核心。

注意这种方式一定要勾上ENABLE NUMA。另外调整配置时注意修改/etc/pve/qemu-server/your_vmid.cpuset中的CPU核心配置

未解决的问题

taskset有bug(taskset from util-linux 2.36.1),使用-a参数绑核部分线程失败

taskset -a中途报错

只有这台机器上的PVE遇到了,重启也不能解决。。。另一台机器完美通过taskset绑核,两者系统是完全一样的,通过dd硬盘克隆的。迷惑。。。。。哪位大佬这知道是什么情况解决吗?

方法2:编辑虚拟机配置文件指定NUMA与CPU核心?

前排警告:numa[n]相关参数是配置虚拟机模拟的numa拓扑,而非跟宿主机之间的映射关系!同时要确保numa[n]中的核心数量内存大小等跟虚拟机设置的核心数量、内存大小一致,否则启动会报错。不推荐使用该方法配置。

经过我实际测试,在PVE 7.1版本下,编辑配置文件中numa[n]相关参数,并不能绑定虚拟机到指定CPU核心或者指定NUMA节点。

参考PVE文档:

numa: <boolean> (default = 0)
    Enable/disable NUMA.

numa[n]: cpus=<id[-id];...> [,hostnodes=<id[-id];...>] [,memory=<number>] [,policy=<preferred|bind|interleave>]
    NUMA topology.

    cpus=<id[-id];...>
        CPUs accessing this NUMA node.

    hostnodes=<id[-id];...>
        Host NUMA nodes to use.

    memory=<number>
        Amount of memory this NUMA node provides.

    policy=<bind | interleave | preferred>
        NUMA allocation policy.

实际上这个numa配置的是虚拟机的numa拓扑,而不是物理机跟虚拟机的映射!

cpus对应的虚拟机配置中的sockets*cores的数量下的映射,而非映射物理机cpu_id

memory对应的虚拟机内部看到的NUMA节点的memory大小

hostnodes我实测发现有时并不能把同一行配置的cpus绑定在同一个宿主机numa上,但是有时又可以。所以我认为hostnodes并不能正确的绑定物理机中的虚拟机线程到对应的numa节点的cpu上

换言之这种绑核方式就像黑盒,该配置不是虚拟机numa拓扑跟物理机的映射,而是给vm manager的一个参考,实际还是看调度,所以看我觉得不如taskset简单粗暴可靠。

编辑虚拟机配置文件 /etc/pve/qemu-server/vmid.conf

在numa条目下方插入一行,内容如下:

numa0: cpus=0-3,hostnodes=0,memory=4096,policy=bind
numa1: cpus=4-7,hostnodes=0,memory=4096,policy=bind

该配置对应的虚拟机设置为sockets:2,cores:4,memory:8192MB,配置之后的numa拓扑为两个numa节点,每个numa节点包含4个核心4G内存

参考


0 条评论

发表评论