ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

虚拟机性能慢?从KVM、QEMU到libvirt的排障指南

虚拟机性能慢?从KVM、QEMU到libvirt的排障指南 虚拟机变慢这是每个用 KVM 的人都会遇到的经典问题。前几天刚帮一个朋友排查 Rocky Linux 10 的虚拟机性能问题现象很典型系统装好之后操作明显卡顿在虚拟机里执行dnf makecache都要等十几秒编译一个小工具时负载直接拉满。朋友的第一反应是“配置不够”准备加 CPU、加内存。我上机看了一眼问了一句“你这虚拟机确定是用 KVM 加速跑的吗”这个问题的答案比加多少核都重要。这篇文章就从“虚拟机很慢”这个最常见不过的排障场景说起。我们会先弄清 KVM、QEMU、libvirt 这几个概念的边界再给出 6 个可以在宿主机和客户机两侧执行的确认命令最后聊一聊如果确实没有跑在 KVM 上要怎么修复以及日常运维时怎么避免踩进同一个坑。1. 这篇文章真正要解决的问题虚拟机慢加配置为什么没用很多人遇到虚拟机慢第一反应就是加 CPU、加内存、换 SSD。这些操作在某些情况下确实有效但有一个前提虚拟机必须已经运行在硬件虚拟化加速之上。如果加速层没有生效再加配置也只是让一台“软件模拟出来的 CPU”跑得快一点点本质上还是在用宿主机的 CPU 去逐条解释、翻译客户机的指令。这种模式的专业叫法是 TCGTiny Code Generator也就是 QEMU 的纯软件模拟模式。它和 KVM 硬件虚拟化之间的性能差距不是百分之二三十而是几倍甚至十几倍。所以排障的顺序应该反过来先确认虚拟化加速是否真正生效再去考虑调整资源规格。确认“虚拟机真的跑在 KVM 上”是整个排障链路里的第一块地基。这篇文章适合这样几类读者在服务器上用 KVM/QEMU/libvirt 管理 Linux 虚拟机尤其是 Rocky Linux、CentOS Stream 这类 RHEL 系系统的运维和开发者遇到虚拟机性能异常怀疑是配置不足但调整后效果不明显的人刚开始接触 KVM想搞清楚“虚拟机”和“模拟器”之间区别的新手。读完这篇文章你会得到一套可以直接执行的确认命令清单以及一份对应的修复思路。2. KVM、QEMU、libvirt排障前需要弄清的三层关系在排查之前建议先把三个经常混着说的词分开。KVMKernel-based Virtual Machine是 Linux 内核里的一个虚拟化模块。它把 CPU 的硬件虚拟化能力Intel VT-x 或 AMD-V暴露给用户态程序使用。KVM 本身不是一套完整的“虚拟机软件”它更像是一个驱动、一个能力接口。你打开/dev/kvm就拿到了利用 CPU 硬件虚拟化指令的入口。QEMUQuick Emulator是一个功能非常完整的模拟器。它既能做纯软件模拟也能配合 KVM 做硬件加速。当它配合 KVM 时CPU 指令不再需要软件翻译而是直接由物理 CPU 的虚拟化扩展来执行性能开销会被压缩到很小。当它单独运行时就只能走 TCG 软件模拟这也是性能瓶颈最常出现的地方。libvirt是管理虚拟机的 API 和守护进程。virsh、virt-manager、virt-install这些工具都建立在 libvirt 之上。它做的事是把 QEMU/KVM 的启动参数、磁盘、网络、VM 定义文件统一管理起来给运维人员一个更友好的操作层。这三个东西的分工可以用下面这张表来看组件角色启动方式排障中关注什么KVM内核模块提供硬件加速能力由内核加载模块名为 kvm_intel / kvm_amd模块是否加载/dev/kvm 是否存在QEMU用户态模拟器虚拟机的“进程本体”手动 qemu 命令或由 libvirt 拉起进程参数里有没有启用 accelkvmlibvirt管理服务统一管理 VM 生命周期systemd 服务 libvirtd服务是否正常VM XML 定义里的 domain type如果你是通过virsh或virt-manager管理虚拟机那么背后真正跑起来的进程仍然是 QEMU但它的加速后端可能是 KVM也可能是 TCG。这两种情况下的表现和定位方式完全不同。理解这一层关系之后很多排障思路就清晰了你以为是虚拟机配置问题实际上可能是虚拟化实现方式的问题。3. 提前判断宿主机是否具备 KVM 硬件虚拟化条件在虚拟机确实很慢的众多原因里有一类特别隐蔽宿主机本身不支持或者没有开启硬件虚拟化虚拟机被迫走了纯软件模拟。判断宿主机是否具备条件一般分三步。第一步检查 CPU 是否支持虚拟化技术。在 x86 架构下需要确认 CPU 标志里有vmx或svmgrep -Eo (vmx|svm) /proc/cpuinfo | sort -u如果输出包含vmx说明 Intel CPU 支持 VT-x如果输出包含svm说明 AMD CPU 支持 AMD-V。如果没有任何输出说明 CPU 要么不支持硬件虚拟化要么在 BIOS/UEFI 中被关闭了。第二步检查 KVM 内核模块是否已加载。lsmod | grep kvm正常加载时应看到类似输出kvm_intel 262144 7 kvm 786432 1 kvm_intel如果是 AMD 机器第一行会是kvm_amd。如果你看到模块已加载但引用计数为 0说明当前没有虚拟机正在使用这个模块可以继续检查后面的环节。第三步检查 /dev/kvm 设备节点是否存在且可访问。ls -l /dev/kvm正常情况下会看到crw-rw-rw- 1 root kvm 10, 232 12月 5 14:22 /dev/kvm如果文件不存在说明 KVM 驱动没有被正确加载或者内核缺少对应支持模块。如果文件存在但当前用户无权限则需要把用户加入kvm组。这三个前置条件都满足之后才能继续讨论“虚拟机的加速器是否生效”这个更深层的问题。很多人一开始就跳到了 QEMU 启动参数却没有注意到宿主机本身就缺少vmx/svm标志这种情况后面怎么调优都没有意义。4. 核心排障确认虚拟机是否真的跑在 KVM 上下面进入正题。假设你已经有一台运行 Rocky Linux 10 的虚拟机并且感觉很慢现在要判断它到底跑在 KVM 硬件加速上还是 QEMU 纯软件模拟上。推荐按下面 6 个命令依次确认。命令 1从宿主机侧看 QEMU 进程的实际参数。如果虚拟机是手动用 qemu 命令启动的直接看进程参数最直观ps -ef | grep qemu如果命令行里包含-accel kvm或-machine accelkvm说明启动时指定了 KVM。如果命令行里没有这两个参数甚至同时出现了-accel tcg那就可以基本判定它没有跑在 KVM 上。如果虚拟机是通过 libvirt 管理的进程命令行动辄几百个字符比较难一眼看清可以改用virsh dumpxml来确认。命令 2通过 libvirt 查看虚拟机的 XML 定义。virsh dumpxml 虚拟机名称 | head -n 3重点看 root 标签里的type属性。如果第一行是domain typekvm说明 libvirt 在创建这台虚拟机时使用了 KVM 域。如果第一行是domain typeqemu说明它走的是纯软件模拟。命令 3在 libvirt 管理的虚拟机上直接观察 QEMU 进程参数。ps -ef | grep qemu | grep 虚拟机名称一条条看命令行里的-accel参数即可。现代 libvirt 版本通常会在 QEMU 命令行里明确带出-accel kvm或-machine accelkvm。这个信息比 XML 更贴近真实运行状态。命令 4从客户机内部查看虚拟化类型。如果宿主机侧没法完全确定直接进虚拟机系统内部看。Rocky Linux 10 这类使用 systemd 的系统自带一个很实用的命令systemd-detect-virt输出kvm说明客户机识别到自己运行在 KVM 之上输出qemu说明它可能跑在纯软件 QEMU 模拟下输出类似microsoft或vmware说明它其实跑在另一层虚拟化里这种情况需要重新向上排查。这个命令的原理是检查 CPUID 和 DMI 信息排障时很顺手不需要额外安装依赖。命令 5用 lscpu 检查客户机里的虚拟化标识。lscpu | grep -i -E hypervisor|virtualization如果看到类似Hypervisor vendor: KVM的输出基本可以确认客户机是 KVM 客户机。如果看到Hypervisor vendor: QEMU则需要进一步分辨是 TCG 还是 KVM因为某些配置下 QEMU 也会设置这个标识。命令 6在客户机里执行 virt-what。virt-what是一个专门用来识别虚拟化环境的小工具比systemd-detect-virt判断得更细。在客户机里执行dnf install -y virt-what virt-what输出kvm表示运行在 KVM 之上。如果同时有多行输出比如kvm加qemu说明是 QEMU 仿真出的 KVM 兼容环境这种环境通常也是 TCG 或嵌套虚拟化性能仍需要进一步观察并不能和物理机上的原生 KVM 划等号。这 6 个命令可以分成两层前 3 个在宿主机侧查后 3 个在客户机侧查。建议排障时先从宿主机侧开始因为宿主机上的进程参数和 XML 定义是可信度最高的一手信息。5. 完整示例从零创建 Rocky 10 虚拟机并确认它跑在 KVM 上前面说了不少判断方法这一节把它串成完整流程。我们用 libvirt 的virt-install工具创建一台 Rocky Linux 10 虚拟机然后在宿主机和客户机两侧分别验证它确实跑在 KVM 上。5.1 安装虚拟化相关软件包在 Rocky Linux 10 上安装 KVM 相关组件最直接的方式是安装虚拟化分组包dnf install -y virtualization也可以按需安装最小集合dnf install -y qemu-kvm libvirt virt-install virt-manager安装完成后启动 libvirtdsystemctl enable --now libvirtd systemctl status libvirtd如果当前用户不在 kvm 组中建议追加进去避免后续无权限访问 /dev/kvmusermod -aG kvm $USER newgrp kvm5.2 准备 Rocky Linux 10 安装镜像这里以 Rocky Linux 10 的 ISO 为例把镜像放到一个固定目录mkdir -p /data/iso cd /data/iso下载链接建议从 Rocky Linux 官网或者离你最近的镜像站获取下面命令中的Rocky-10-*.iso需要替换成你实际下载的文件名。要注意的是目录下只能有一个匹配该通配符的 ISO 文件否则virt-install会因参数歧义而报错。5.3 创建 KVM 虚拟机使用virt-install创建虚拟机参数里的关键点是--virt-type kvmvirt-install \ --name rocky10-test \ --memory 4096 \ --vcpus 4 \ --disk path/var/lib/libvirt/images/rocky10-test.qcow2,size40,formatqcow2 \ --cdrom /data/iso/Rocky-10-*.iso \ --os-variant rocky10 \ --network networkdefault \ --graphics vnc \ --virt-type kvm这里有一个很容易被忽略的细节如果宿主机满足 KVM 条件--virt-type kvm会让virt-install创建domain typekvm的虚拟机但如果宿主机不满足 KVM 条件安装过程可能会回退到--virt-type qemu导致你的虚拟机最终跑在软件模拟上。这个现象非常隐蔽因为安装过程并不会明显报错你只会觉得后续使用很慢。另外--os-variant rocky10这个参数并不是所有 libvirt 版本都能识别。如果你的环境提示不支持该变体名可以先执行下面命令查询本机支持的 osinfo 列表osinfo-query os | grep -i rock选择最接近的版本名称即可。如果完全没有匹配项也可以去掉--os-variant参数安装到系统类型选择步骤时手工指定。5.4 宿主机侧验证虚拟机创建并完成系统安装后回到宿主机执行virsh list --all virsh dumpxml rocky10-test | grep domain type预期输出是domain typekvm如果看到的是domain typeqemu说明这台虚拟机没有跑在 KVM 上需要回到第 6 节修复。再检查 QEMU 进程参数ps -ef | grep qemu | grep rocky10-test命令行里如果包含-accel kvm说明虚拟机确实启用了 KVM 加速。5.5 客户机侧验证进入 Rocky Linux 10 虚拟机内部执行systemd-detect-virt预期输出是kvm。如果想更精确地识别再执行dnf install -y virt-what virt-what预期输出同样包含kvm。到这里一台虚拟机从创建到验证的完整流程就走完了。你会发现整个流程里最重要的事情就是“创建时显式指定加速器”和“创建后主动验证”。6. 如果确实没跑在 KVM 上怎么修复如果经过前面的检查确认虚拟机真的跑在 TCG 或纯 QEMU 模拟模式要根据不同场景选择修复方式。场景一手动用 qemu 命令启动的虚拟机启动参数里少了 KVM。这种情况最简单把启动命令里的-machine acceltcg改成-machine accelkvm或者加上-enable-kvm然后重启虚拟机。注意前提是宿主机确实具备 KVM 条件否则加参数会直接报错无法启动。场景二libvirt 管理的虚拟机XML 里 domain type 是 qemu。可以用virsh edit修改虚拟机定义把 root 标签里的typeqemu改成typekvmvirsh edit 虚拟机名称保存后重启虚拟机。这里要注意只改type属性还不够建议同时检查 XML 里是否有 CPU 相关的合理配置比如是否保留了原生的 host-passthrough 或 host-model避免客户机里的 CPU 特性发生变化导致应用兼容问题。修改 XML 属于生产环境变更操作前建议先备份原文件virsh dumpxml 虚拟机名称 /path/to/backup/rocky10-test.xml场景三宿主机本身是一台虚拟机属于嵌套虚拟化。如果你的“宿主机”是云服务器或者 VMware 里的虚拟机那么 KVM 能否使用取决于上层虚拟化是否透传了虚拟化指令。比如 VMware 里需要开启“向客户机操作系统公开硬件辅助的虚拟化”云厂商则要看实例类型是否支持嵌套虚拟化。这种情况不建议硬开 KVM更稳妥的做法是更换支持嵌套虚拟化的云主机或者改用物理机。无论哪种场景修复后都要回到第 4 节里的验证命令重新确认尤其是virsh dumpxml里的 domain type以及客户机内部的systemd-detect-virt。已经安装好的客户机系统从 TCG 切到 KVM一般不需要重装Rocky Linux 10 在 KVM 场景下默认使用的 virtio 驱动通常可以无缝工作但生产环境操作仍然要准备好回滚方案。7. 常见问题虚拟机很慢的典型原因排查表把“虚拟机很慢”当成一个综合症状来看KVM 加速缺失只是其中一个原因。这里整理一份常见的排查表方便你在现场快速对照。问题现象可能原因排查方式解决方案虚拟机整体反应迟钝客户机里 CPU 持续高负载没跑在 KVM 上走了 TCG 软件模拟宿主机执行 ps 查看 qemu 参数客户机执行 systemd-detect-virt创建时指定 --virt-type kvm或修复 XML domain type安装系统时就非常慢进度条几乎不动创建 VM 时回退到 qemu 类型或宿主机缺少 /dev/kvmls -l /dev/kvmvirt-install 加 --virt-type kvm确保宿主机硬件虚拟化开启重新创建或编辑 VM 定义磁盘 IO 慢客户机磁盘显示为 /dev/sdX 而不是 /dev/vdX磁盘总线用的是 IDE 或 SATA而不是 virtio客户机执行 lsblk -d -o name,tran磁盘总线改用 virtio必要时做磁盘离线迁移网络吞吐低延迟抖动明显虚拟网卡模型为 e1000 或 rtl8139而非 virtio-net客户机执行 ethtool -i 网卡名把网卡模型改为 virtiovirsh dumpxml 显示 typeqemu但不想重装系统创建时未显式指定 --virt-type kvm检查宿主机 CPU 是否支持 vmx/svm通过 virsh edit 修改 domain type并确认 /dev/kvm 权限CPU 频率明显低于标称频率单核跑分偏低宿主机 CPU 节能策略或客户机 CPU governor 为 powersave客户机查看 cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor使用 performance governor或调整宿主机 BIOS 电源策略多核性能上不去单核却正常vCPU 被限制在同一个物理核心上或者拓扑不匹配virsh vcpuinfo 查看 vCPU 绑定情况合理配置 vCPU 和 NUMA必要时做 vCPU 绑定分散到不同核心这张表覆盖了比较常见的几种“慢”的表现它们在症状上很相似但定位路径完全不同。遇到问题先不要急着加资源先按表格里的排查方式走一遍往往能省下大量时间。8. 最佳实践让 KVM 虚拟机保持高效和稳定这一节整理几条对 Rocky Linux KVM 场景最实用的长期经验。8.1 创建虚拟机时养成显式指定类型的习惯无论使用virt-install还是virt-manager都要在命令或界面上确认虚拟化类型是 KVM。不要让系统自动判断自动判断在条件不满足时会悄悄回退到 QEMU这正是很多性能问题的来源。建议在安装脚本里加一条宿主机预检命令#!/bin/bash # 文件路径/usr/local/bin/check-kvm-host.sh if [ ! -e /dev/kvm ]; then echo 警告/dev/kvm 不存在无法使用 KVM 加速 exit 1 fi grep -Eo (vmx|svm) /proc/cpuinfo | sort -u | grep -q . || { echo 警告CPU 未开启硬件虚拟化 exit 1 } echo KVM 环境检查通过8.2 磁盘和网络设备尽量使用 virtioKVM 场景下virtio 半虚拟化设备的性能通常明显优于 IDE 和 e1000。创建虚拟机时磁盘总线指定busvirtio网络模型指定modelvirtio。Rocky Linux 10 的内核自带了 virtio 驱动默认安装后就能识别不需要额外加载模块。排障时如果发现客户机内部磁盘是/dev/sda而不是/dev/vda通常说明磁盘总线用的是 IDE 或 SATA。这种情况在系统已装好的情况下迁移比较麻烦需要离线操作评估好业务影响再动。8.3 一定要给客户机配置时间同步虚拟机的性能问题往往和时钟漂移混在一起。KVM 客户机默认的时钟源通常是 kvm-clock不需要额外配置但要确保系统时间同步服务开启。在 Rocky Linux 10 中建议使用 chronydnf install -y chrony systemctl enable --now chronyd timedatectl set-ntp true时间不同步在负载高时会带来系统调用层面的异常等待现象上很像性能问题但本质上是时钟问题。8.4 用监控数据代替感觉遇到“虚拟机很慢”的时候不要凭经验猜。先采集数据宿主机侧virsh vcpuinfo、virt-top、sar。客户机侧top、iostat、vmstat。用数据区分是 CPU 慢、磁盘慢还是网络慢。KVM 排障有个特点问题往往隔离在某一层。CPU 慢大概率是加速器问题磁盘慢大概率是驱动或存储池问题网络慢大概率是网卡模型性能问题。只有先锁定层级才能避免做无用功。8.5 维护一份最小性能基准在日常运维中建议给每类虚拟机保存一份“创建时关键参数”的文档或者脚本特别是--virt-type、CPU 型号、磁盘总线、网卡模型这几个参数。这样下次再遇到慢的问题可以快速对照“是不是本来就没跑在 KVM 上”这个问题只需要 10 秒就能回答。9. 总结与进一步排查方向回到文章开头那个场景。朋友的 Rocky Linux 10 虚拟机最后确认是在创建时没有显式指定--virt-type kvm系统在缺少检测的情况下回退到了 QEMU 纯软件模拟。调整成 KVM 类型后编译任务耗时从十几分钟降到两三分钟这比单纯加核加内存有效得多。所以当你的虚拟机再次变慢时先问自己三个问题宿主机支持硬件虚拟化吗/dev/kvm存在吗QEMU 进程真的用了 KVM 加速吗这三个问题确认完之后才轮到加配置、调优驱动、优化存储这些后续动作。进一步可以研究的方向包括KVM 的 CPU 拓扑与 NUMA 绑定、virtio-blk 与 virtio-scsi 的选择、libvirt 的 cgroup 资源限制以及嵌套虚拟化场景下的性能损耗评估。对于 Rocky Linux 10 这类基于较新内核的系统KVM 虚拟化的开箱体验已经足够好但真正理解加速器的原理才能在排障时不走弯路。建议把上面的确认命令和排查表收藏备用下次遇到“虚拟机很慢”的问题直接从 KVM 确认开始。
返回列表