简介:一份面向PVE8虚拟机用户的高级参数配置源码包,以可运行代码形式收录虚拟机创建过程中的关键设置项,适合运维人员、虚拟化学习者及开发者参考,用于优化虚拟机性能与功能。压缩包共3个文件,由HTML页面、inscode项目配置及辅助代码文件组成,整体大小仅6KB,轻量易读。目前已有158人学习,可作参数调优参考。源码内容覆盖开机自启动、操作系统镜像选择、系统配置中的显卡、机型、BIOS与EFI存储、格式及SCSI控制器,以及磁盘总线与设备、缓存策略、SSD仿真和丢弃选项;同时涉及CPU类别、内存管理和网络配置。另有virtio-win驱动与qemu-guest-agent的安装使用指南,可帮助读者理解各项高级参数对虚拟机性能与兼容性的具体影响,优化自身部署方案,特别适合用于构建高性能虚拟化环境。
1. PVE8 虚拟机高级参数:别让网页向导框住你的配置
在 PVE8 里通过网页向导创建虚拟机很简单,但生产环境一跑就露馅:多核虚拟机吃不满宿主 CPU,想在虚拟机里再开个虚拟机总是报错,qcow2 磁盘删了文件只增不减。这些问题在网页面板里基本找不到入口,因为它们都藏在 PVE8 虚拟机的高级参数里。所谓高级参数,指的是 /etc/pve/qemu-server/ 目录下每个虚拟机对应的 .conf 文件中,那些图形界面没有直接暴露的键值:CPU 类型、嵌套虚拟化开关、I/O 线程、PCIe 直通、QEMU 原生参数透传等。这篇文章按“配置文件 → CPU/内存 → 磁盘/直通 → 避坑 → 可运行脚本”的顺序展开,适合自己维护 PVE8 单机或小集群的运维,也适合被向导折腾到快放弃的入门者。
2. 先把配置文件读透:VMID.conf、qm set 与 qm showcmd 的配合
2.1 配置文件在哪:/etc/pve/qemu-server/ 的结构
PVE8 里每台虚拟机的完整配置不在数据库里,而是一个以虚拟机 ID 命名的文本文件,放在 /etc/pve/qemu-server/ 下。比如 ID 为 100 的虚拟机,对应文件就是 100.conf。用 cat 直接查看是排查参数问题的第一步,因为网页上看到的选项都是这个文件的某个子集。
# 查看 ID 为 100 的虚拟机完整配置 cat /etc/pve/qemu-server/100.conf # 列出当前宿主机上所有虚拟机配置文件 ls -l /etc/pve/qemu-server/我见过不少人在网页面板里反复找某个参数,找了半天没找到,其实参数就安静地躺在 conf 文件里。PVE8 的 conf 格式非常简单,每行一个键值对,键和值之间用冒号加空格分隔。一个典型的配置文件看起来是这样:
cores: 4 memory: 8192 name: web-server ostype: l26 net0: virtio=AA:BB:CC:DD:EE:FF,bridge=vmbr0 virtio0: local-lvm:vm-100-disk-0,discard=on,iothread=1cores 是 vCPU 核数,memory 是内存 MB 数,net0 是第一个网卡,virtio0 是第一块 virtio 磁盘。这里有个容易误解的点:iothread=1写在磁盘行末尾,表示该磁盘启用独立的 I/O 线程。这个参数在网页向导里也能看到,但很多人不知道它实际上是一行 conf 里的子参数,和虚拟机整体的某个开关不是一回事。看配置文件的习惯一定要养成,因为后面所有高级参数排查都从读 conf 开始。
另外,/etc/pve/ 是个共享集群文件系统,不是普通磁盘目录。你在一台节点上改配置,其他节点也会同步看到。好处是配置文件天然一致,坏处是如果你手滑写坏了,可能影响整个集群的配置同步。所以改配置前先备份一行命令,这是后话。
2.2 改参数用 qm set,不要裸手改 conf
读配置用 cat,改配置我建议只用 qm set,而不是用文本编辑器直接改 conf 文件。原因有两个:qm set 会做参数合法性校验,写错类型会当场报错;qm set 会把参数交给 PVE 的服务端逻辑统一处理,避免和集群同步打架。直接改文件也能生效,但一旦格式写错,虚拟机可能直接起不来。
# 用 qm set 一次性设置多个参数 qm set 100 --cpu host --cores 4 --memory 8192 --nested 1 # 修改磁盘参数行 qm set 100 --virtio0 file=local-lvm:vm-100-disk-0,discard=on,iothread=1 # 删除某个参数(这里删除 balloon 设置,即关闭限制) qm set 100 --delete balloon每次 qm set 只改你指定的键,未指定的其他键保持原样,这点比手改文件安全得多。参数格式上,所有布尔值用 0 或 1 表示,不要写 true/false,也不要写 yes/no,混杂写法在部分版本里会被识别成字符串,导致校验失败。--delete用来删参数,键盘上敲熟这招,排错的时候能省不少事。
qm set 执行后建议立刻用 qm config 看一遍结果,确认参数确实写进去了。qm config 的输出格式和 conf 文件内容基本一致,这是改完参数后的第一道验证。
2.3 验证生效:qm config 只是第一步,qm showcmd 才是最后凭证
qm config 看到的是 PVE 层理解的参数,而真正驱动虚拟机起来的是 QEMU 进程。从 PVE 参数到 QEMU 命令行之间还有一层转换逻辑,这层转换是个黑匣子,官方界面不会告诉你到底给 QEMU 传了什么。qm showcmd 就是为这件事准备的,它把最终拼出来的 QEMU 启动命令行完整打印出来。
# 查看虚拟机 100 的 PVE 层配置 qm config 100 # 查看 PVE 最终会交给 QEMU 的完整命令行 qm showcmd 100 # 换行输出,看得更清楚 qm showcmd 100 --prettyqm showcmd 不会真正启动虚拟机,只是把 QEMU 命令行打印到标准输出。排错时看它比看网页可靠得多。比如你设置了 nested 虚拟化,但 CPU 类型忘记改成 host,qm showcmd 的输出里就不会出现 vmx 或 svm 标志位,问题一眼就能看出来。
这里提一个我常用的习惯:改高级参数后,先 qm config 确认 PVE 理解正确,再 qm showcmd 确认 QEMU 拿到正确参数。两道验证都过了,再启动虚拟机。跳过 showcmd 直接启动,等于把黑匣子留到第二天,翻不翻车完全看运气。
3. CPU 与内存高级参数:配额、嵌套与大页怎么设才对
3.1 cpulimit 与 cpuunits:CPU 配额和调度的真实含义
PVE 里 vCPU 数量决定虚拟机看见几个核,但真正决定它能吃到多少 CPU 时间的是 cpulimit 和 cpuunits 两个参数。cpulimit 表示该虚拟机最多能占用多少个物理核心的百分比,比如 cpulimit 值为 200 表示最多占用 2 个物理核心的全部时间。cpuunits 表示 CPU 调度权重,多台虚拟机抢 CPU 时按权重分配,默认值 100,把某台虚拟机调到 1000,它在抢 CPU 时能分到更大的份额。
# 限制虚拟机最多使用 1.5 个物理核心 qm set 100 --cpulimit 150 # 把虚拟机 CPU 权重调高,在资源竞争时获得更多份额 qm set 100 --cpuunits 500 # 宿主上所有 VM 的 cpuunits 总和 # 一般不建议所有虚拟机都调大,否则等于没调cpulimit 设为 0 表示不限制,这是默认状态。生产环境常见的误区是给虚拟机分配了 8 核,但忘记这个分配只是虚拟化层的“可见核数”,没有 cpulimit 时虚拟机确实能用满 8 核。反过来,有些面板上显示 CPU 使用率 100%,实际是单核跑满,另外几个核闲着,这时不是 cpulimit 的问题,而是应用本身没做多线程。
想确认 CPU 配额有没有生效,同样用 qm config 看输出里的 cpulimit 行。如果值是 0,说明没限制。另一个值得记的点:cpuunits 的默认值 100 足够用了,除非你真的有个虚拟机比其他虚拟机优先级高很多,否则不要全调大。全调大以后,宿主物理机 CPU 争抢时所有虚拟机表现都变差,这是血泪经验。
3.2 nested 与 CPU type host:虚机里再开虚机的完整条件
nested 即嵌套虚拟化,在虚拟机里再跑 KVM,比如在 PVE 虚拟机里再装一个带虚拟化的系统做测试。前提条件有两个:宿主机的 CPU 要支持虚拟化,且已加载嵌套相关模块;虚拟机的 CPU 类型必须设为 host,否则 CPU 指令集里的 vmx 或 svm 标志位不会传给虚拟机。
# 设置 CPU 类型为 host,并把嵌套虚拟化打开 qm set 100 --cpu host --nested 1 # 进入虚拟机后检查有没有虚拟化标志位(Intel 看 vmx,AMD 看 svm) # 在虚拟机终端里执行 grep -E "vmx|svm" /proc/cpuinfo只开 nested 不换 CPU 类型是最常见的翻车操作。默认 CPU 类型是 kvm64,这种虚构 CPU 为了兼容性刻意不暴露虚拟化标志位,guest 里的 KVM 自然起不来。另外,宿主是 Intel 还是 AMD,对应模块名不同,但 PVE 层面不需要区分,CPU type 选 host 后会自动透传宿主 CPU 的特性。
嵌套虚拟化的性能损失是客观存在的,我一般只建议在测试环境开。生产环境把嵌套开给某个虚拟机,等于给那个虚机开启了一个小的不可控的虚拟化入口,和宿主争抢资源不说,镜像迁移到其他型号 CPU 的宿主时还可能出现指令集不兼容,虚拟机直接拒绝启动。如果只是为了跑某些需要 VT 检测的老软件,先想想有没有别的路子,不要一条路走到黑。
3.3 hugepages 与 NUMA:内存级参数的收益与代价
hugepages 即大页内存,把物理内存预先切成大尺寸页,减少 CPU 的 TLB 未命中开销。PVE8 的 conf 里用 hugepages 键设置,值表示页数量,2MB 页和 1GB 页有不同写法,常用 1024 让内存区换算成 2MB 大页配合使用。启用大页后,内存不能热插拔,balloon 也要关掉,否则 QEMU 的内存管理和大页预分配机制会互相干扰。
# 关掉 balloon,启用 2MB 大页,打开 NUMA qm set 100 --balloon 0 --hugepages 1024 --numa 1 # 查看大页是否分配成功 # 在宿主机上执行 cat /proc/meminfo | grep HugePagesNUMA 参数让 guest 感知物理主机的 NUMA 拓扑,这在多路物理 CPU 的机器上有实际收益:虚拟机内存访问可以尽量落在本节点。但对于单路 CPU 或虚拟机 vCPU 数很少的机器,开 NUMA 意义不大,有时还带来跨节点内存访问的额外开销。判断依据很简单:先看宿主机是不是多路,不是就优先关掉 NUMA。
大页也一样,不是默认开启就好。io 密集或数据库类虚拟机放物理内存大幅提升性能的情况,值得开大页;一般测试机开大页纯粹是给自己找麻烦,开机时预留内存失败会导致虚拟机起不来,日志里提示 hugepage 分配失败,只能老老实实回退。我见过有人在 16GB 内存的宿主机上给 8GB 虚拟机开大页,结果还开了另一台 8GB 虚拟机,第二台怎么都起不来。算一下总账再决定。
4. 磁盘与直通高级参数:virtio、iothread、hostpci 与 args
4.1 磁盘参数组合:iothread、discard、ssd、cache 的搭配
磁盘是高级参数的重灾区,因为一个磁盘行里塞了好几个子参数,关系还容易搞混。virtio0 后面的discard=on让 QEMU 转发 guest 的 TRIM 命令给底层存储,ssd=1让 guest 认为底层是 SSD 并自动开启一些闪存优化策略,iothread=1把这块盘的 I/O 处理放到独立线程。cache 模式决定读写缓存策略,PVE 中的常见取值有 none、writeback 和 unsafe。
# 给虚拟机的第一块 virtio 磁盘开启 discard、ssd 仿真和独立 IO 线程 qm set 100 --virtio0 file=local-lvm:vm-100-disk-0,discard=on,ssd=1,iothread=1,cache=none # 第二块盘只开 discard,不配 iothread qm set 100 --virtio1 file=local-lvm:vm-100-disk-1,discard=oniothread 的设计目的是让磁盘中断和虚拟 CPU 解耦,减少对 guest vCPU 调度的干扰。但这个参数的隐含约束很多人不了解:iothread 只对 virtio 块设备有意义,IDE 或 SATA 磁盘配上 iothread 没有效果,甚至可能让 QEMU 启动时报参数错误。而且 iothread 要求虚拟机至少配置 2 个 vCPU,单核虚拟机配上 iothread 是自找麻烦。
cache=none 表示绕过宿主机 page cache 直写,配 Ceph 或本地 ZFS 时比较常见,配合 iothread 能减少双重缓存造成的内存浪费。cache=unsafe 只适合临时测试环境,guest 认为写入成功实际上数据可能没落地,一断电数据全没。生产环境绝大多数情况用 cache=none 或保持 PVE 默认即可,不建议为了追求“更快”盲目改写回。
4.2 hostpci 直通:前置条件、格式与现场确认
hostpci 是硬件直通的入口,把宿主物理机上的一个 PCI 设备直接划分给虚拟机使用。最常见的场景是 GPU 直通和某些特殊板卡直通。前置条件比 PVE 本身多一层:BIOS 里要开 VT-d,内核启动参数要加 iommu 相关选项,设备还要能被 vfio 驱动接管。少任何一个条件,直通都会有玄学问题。
# 查看 PCI 设备编号 lspci -nn | grep -i "vga\|display" # 配置直通:0000:01:00.0 是 PCI 地址 qm set 100 --hostpci0 0000:01:00.0,pcie=1,x-vga=1 # 确认设备已经被隔离给 vfio lspci -nnk -s 01:00.0hostpci0 后面的参数里,pcie=1 让虚拟机的 PCIe 设备以 PCIe 形态呈现,x-vga=1 表示把该设备作为虚拟机的主显示输出。配置直通后,这个设备对宿主机不可见,不能再被宿主或其他虚拟机使用。所以直通前要确认设备地址写对,lspci 输出和 conf 里的地址不一致时,虚拟机启动会在初始化设备阶段卡住。
直通是最容易出现“现象千奇百怪”的领域,网卡丢包、GPU 驱动报错、虚拟机启动黑屏,大概率都要回到 lspci -nnk 看驱动绑定情况。设备和 vfio 没绑上,直通配置就像是给 PCI 设备买了票但没进站,虚拟机内当然看不到设备。固定排查顺序:先查 BIOS VT-d,再查内核参数,最后查 lspci -nnk,不要跳步。
4.3 args 参数:把 QEMU 原生参数写进 PVE 配置的最后通道
args 是 PVE 给用户留的最后一扇窗,你可以把 PVE 没在界面里暴露的 QEMU 原生参数直接写进 conf。比如某些特殊设备模拟参数、自定义 firmware 加载参数,PVE 没有专门配置项时,都靠 args 解决。
# 添加自定义 QEMU 设备参数(示例:额外挂一个 PCI 设备) qm set 100 --args '-device vfio-pci,host=0000:00:1f.6' # 在 args 里修改 CPU 特性,比如强制开启某指令集 qm set 100 --args '-cpu host,+vmx'args 参数的赋值是原样传给 QEMU 命令行的,所以写错以后报错信息会直接出现在 QEMU 的启动日志里。这里有个重要习惯:用了 args 以后,qm showcmd 就不再是参考,而是必须执行,看最终生成的命令行和你写的参数是不是一致。PVE 在转发 args 时可能做转义处理,原样字符串是理想情况,实际可能受引号和空格影响,showcmd 能看出端倪。
args 和 GUI 已有参数可能产生冲突。比如设置面板里已经把 CPU 类型设为 host,args 里又写 -cpu 参数,QEMU 解析命令行时后出现的不一定覆盖前者,两个 CPU 参数同时存在会让 QEMU 直接报错,这种冲突用 showcmd 一眼就能发现。建议 args 只放 PVE 没有对应选项的参数,已有的配置项别在这里画蛇添足。
5. 高级参数避坑:5个常见的翻车点与排查路径
5.1 网卡选错型号,虚拟网卡吞吐高时 CPU 占用异常高
现象:虚拟机流量稍大,宿主上对应的 QEMU 进程 CPU 占用直线上升,ping 延迟抖动,面板看负载不高但实际体验卡顿。
原因:虚拟机网卡型号用了 e1000,这是纯软件模拟的百兆千兆网卡,每个网络包都要经过完整的设备模拟流程,宿主机侧开销极大。virtio 是半虚拟化网卡,guest 驱动直接操作共享环形队列,宿主机侧开销明显更低。不少人在向导里为了“兼容性”手动选了 e1000,代价就是网络吞吐一高宿主机 CPU 就失控。
解决:把网卡型号改成 virtio,虚拟机内安装或更新 virtio 驱动。改之前先把 virtio 驱动装好,改完网卡型号网卡会重新挂载,配置静态 IP 的虚拟机需要确认网卡名是否变化。
# 修改虚拟机 100 的第一个网卡为 virtio qm set 100 --net0 virtio=AA:BB:CC:DD:EE:FF,bridge=vmbr05.2 开了 discard 以后,qcow2 依然只增不减
现象:conf 里磁盘行写了 discard=on,虚拟机里删了大量文件,但宿主上的 qcow2 文件体积纹丝不动。
原因:discard=on 只是让 QEMU 层面的块设备转发 TRIM 命令,guest 里的文件系统不去发 TRIM,等于上游命令压根没到虚拟磁盘。Linux 的 ext4 默认不会自动发 discard,要么手动执行 fstrim,要么挂载参数里写 discard。另外 SSD 仿真参数 ssd=1 没开,部分 guest 会认为底层是机械盘而停用相关优化,也可能影响 TRIM 行为。
解决:磁盘行同时写 discard=on,ssd=1,然后进虚拟机手动 fstrim 一次验证效果。
# 宿主机上修改磁盘参数 qm set 100 --virtio0 file=local-lvm:vm-100-disk-0,discard=on,ssd=1 # 虚拟机内执行 TRIM fstrim -vafstrim 执行完后回到宿主看 qcow2 文件大小,如果变小说明链路通了。想自动回收,在 guest 里启用 fstrim 的定时服务即可。
5.3 nested 开了还是没法在虚机里开虚机
现象:conf 里 nested=1 已设置,但虚拟机里 /proc/cpuinfo 看不到 vmx 或 svm 标志,KVM 模块加载报错。
原因:nested 只是总开关,还得让 CPU 型号透传虚拟化标志位。默认的 kvm64 CPU 模型不暴露 vmx/svm,虚拟机的 CPU type 必须是 host 才会把宿主 CPU 的完整特性传给 guest。
解决:看 qm config 的 cpu 行是不是 host,不是就先改 CPU 类型再启动虚拟机。
# 查看 CPU 类型 qm config 100 | grep ^cpu # 改为 host 并确认 nested 为 1 qm set 100 --cpu host --nested 1改完务必重启虚拟机,CPU 型号是启动时定死的,在线改不会生效。
5.4 iothread 一排上,虚拟机启动就失败
现象:在磁盘行加了 iothread=1,虚拟机启动失败,QEMU 报参数错误,或启动中途磁盘不可用。
原因:iothread 对磁盘控制器类型和 vCPU 数量有约束。磁盘必须是 virtio 块设备,IDE/SATA 不行;虚拟机 vCPU 数至少要 2 个。单核虚拟机配 iothread,QEMU 初始化时就撑不住。
解决:先检查磁盘是不是 virtio,虚拟机 cores 是否大于等于 2,不满足则先改基础配置再加 iothread。
# 确认 vCPU 数量和磁盘类型 qm config 100 | grep -E "^cores|^virtio0"如果两块盘,一块是 IDE 一块是 virtio,只给 virtio 盘开 iothread 是可以的,但要注意 IDE 盘仍承担系统盘角色时,整体性能并不会因为 iothread 有本质提升,先把系统盘也迁到 virtio 再说。
5.5 手改 conf 后参数莫名丢失
现象:用文本编辑器直接改了 /etc/pve/qemu-server/100.conf,加了好几个参数,重启虚拟机后发现部分参数没了,有时 PVE 还提示配置格式错误。
原因:PVE 的 qm 命令会维护自己的配置缓存,直接编辑文件不经过 qm 逻辑,某些键没被 PVE 识别就会在后续写回时被覆盖。另一个常见问题是同一行键值出现多次,PVE 解析时只认最后一次匹配,QEMU 实际拿到的可能是你认为已经删掉的那个旧值。
解决:一律用 qm set 修改参数,避免直接编辑 conf。如果非要在命令行操作,先备份再编辑,编辑后立即用 qm config 验证一遍,再手动重启相关服务让配置重新加载。
# 备份配置 cp /etc/pve/qemu-server/100.conf /root/100.conf.bak # 严格用 qm set 修改,不要直接改文件 qm set 100 --nested 1手改文件对我来说是纯踩坑,现在我唯一的动手路径是 qm set 加 qm showcmd 验证,这条路走通以后再也没遇到过参数莫名消失的情况。
6. 批量应用高级参数的可运行脚本:一套可复制的检查思路
6.1 脚本:读取、比对、套用、验证四步走
前面的参数都是单条设置,但我实际管理多台虚拟机时,希望有一份可运行的脚本,能按规划批量套用并自动核对。下面这个脚本是给已经存在的虚拟机批量设置常用高级参数的,包括 CPU 类型、嵌套、关闭 balloon、开启 NUMA。脚本会在写入前后分别读取配置,确保每一步都有据可查。
#!/usr/bin/env bash # 批量套用 PVE8 虚拟机高级参数,适用于已存在的 VM # 用法: ./apply_pve_params.sh <VMID> set -euo pipefail VMID="${1:?用法: $0 <VMID>}" # 期望参数表,按需修改 EXPECTED_CPU="host" EXPECTED_NESTED="1" EXPECTED_BALLOON="0" EXPECTED_NUMA="1" # 读取当前配置,VMID 不存在时直接退出 if CUR="$(qm config "$VMID" 2>/dev/null)"; then : else echo "VMID $VMID 不存在或不可访问" >&2 exit 1 fi # 从 "key: value" 输出里取值,避免依赖列位置 get_conf_value() { local key="$1" awk -v k="$key" -F': ' '$1==k {sub(/^[^:]*: */, ""); print; exit}' \ <<<"$CUR" } # 组装修复参数,只放需要变动的项 apply_args=() cur_cpu="$(get_conf_value cpu)" if [[ "$cur_cpu" != "$EXPECTED_CPU" ]]; then apply_args+=(--cpu "$EXPECTED_CPU") fi cur_nested="$(get_conf_value nested)" if [[ "${cur_nested:-0}" != "$EXPECTED_NESTED" ]]; then apply_args+=(--nested "$EXPECTED_NESTED") fi cur_balloon="$(get_conf_value balloon)" if [[ "${cur_balloon:-1}" != "$EXPECTED_BALLOON" ]]; then apply_args+=(--balloon "$EXPECTED_BALLOON") fi cur_numa="$(get_conf_value numa)" if [[ "${cur_numa:-0}" != "$EXPECTED_NUMA" ]]; then apply_args+=(--numa "$EXPECTED_NUMA") fi # 需要修改时先展示再执行 if [[ ${#apply_args[@]} -gt 0 ]]; then echo "准备修改: qm set $VMID ${apply_args[*]}" # 简单确认,生产环境可按需替换为自动执行 read -r -p "确认执行? [y/N] " answer if [[ "$answer" != "y" && "$answer" != "Y" ]]; then echo "已取消" exit 0 fi qm set "$VMID" "${apply_args[@]}" else echo "所有参数已符合预期,跳过写入" fi # 最后用 showcmd 看一下 QEMU 最终拿到的启动参数 echo "----- QEMU 启动命令关键行 -----" qm showcmd "$VMID" --pretty | head -30脚本核心是“期望状态与当前状态比对”,只有差异项才执行 qm set,避免每次运行都重复写入。get_conf_value 用 awk 按 key 精确匹配,比 grep 后手工切割列更耐格式变化。qm set 接收数组形式的参数,所以脚本里先组装 apply_args 再一次性执行,这个写法比拼接字符串安全得多,参数里出现空格也不会被拆碎。
注意--balloon "$EXPECTED_BALLOON"期望值为 0 时,脚本会正确把它当成字符串传给 qm set。如果期望值是 1,即允许 balloon,conf 里的 balloon 键可能根本不存在,所以取默认值时用${cur_balloon:-1},缺少键按值为 1 处理。同理 numa 和 nested 默认按 0 处理。确认后双击执行,脚本跑完会打印 QEMU 启动命令的关键行,人工再扫一眼有没有明显异常。
6.2 参数清单:一张够用的 conf 高参速查表
日常维护中我反复用到的参数集中放在下面这张表里,适用场景和要不要常开都写在备注里。
| 参数 | 示例值 | 作用 | 备注 |
|---|---|---|---|
| cpu | host | 把宿主 CPU 特性透传给 VM | 开嵌套必设,迁移宿主要谨慎 |
| nested | 1 | 开启嵌套虚拟化 | 测试环境再开 |
| cpulimit | 200 | 最多占用 2 个物理核 | 0 为不限 |
| cpuunits | 500 | CPU 调度权重 | 默认 100,勿全员调大 |
| balloon | 0 | 关闭内存气球 | 配合大页必须关 |
| hugepages | 1024 | 使用 2MB 大页 | 内存足够才开 |
| numa | 1 | 让 VM 感知 NUMA 拓扑 | 多路物理 CPU 再开 |
| iothread | 1 | 磁盘 IO 独立线程 | 需 virtio 盘 + ≥2 vCPU |
| discard | on | 转发 TRIM | 配 ssd=on 效果更好 |
| ssd | 1 | 让 guest 识别为 SSD | 与软件磁盘配合使用 |
| hostpci0 | 0000:01:00.0 | PCI 设备直通 | 确认先绑 vfio |
| args | -cpu host,+vmx | 透传 QEMU 原生参数 | 用 showcmd 验证 |
我把这表存在自己服务器上,每次给新虚拟机套参数就照表过一遍,优先选择不需要额外硬件条件的项目。遇到一台虚拟机特别吃 CPU,我先看 cpulimit 是不是被上个值班的人偷偷限制过;遇到磁盘膨胀,第一反应看 discard 有没有配,再进 guest 跑 fstrim;遇到虚机里起虚机失败,直接 grep conf 里的 cpu 和 nested 两行。这套排查路径走了大半年,翻车率比我早期纯靠网页面板低得多。
最后补一个习惯:任何重要虚拟机在改高级参数前,先跑一遍 qm showcmd 把原始命令行存成文件,出问题时回来对比。这个习惯救过我一次,某次调了磁盘 cache 模式后虚拟机 IO 性能骤降,回头对比 showcmd 才发现多了一个没见过的参数,清掉就恢复正常。希望帮到你。
本文还有配套的精品资源,点击获取