ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

虚拟机变慢先查KVM:Rocky 10性能排障指南

2026/9/8 8:24:21 拓冰建站 浏览量
虚拟机变慢先查KVM:Rocky 10性能排障指南 手里的 Rocky 10 虚拟机最近开始卡得离谱CPU 在宿主机里动不动就 100%Guest 系统里打开一个配置界面都要等好几秒应用更是一顿一顿的。一开始我以为是资源不够先后加了 vCPU 和内存结果几乎没有改善。后来抱着试试看的心态进虚拟机里执行了一个命令才确认一个让人哭笑不得的事实这台虚拟机根本没有跑在 KVM 上而是退回了纯软件模拟。虚拟机的“慢”有很多种原因但如果你问我在 Rocky 10 这种 Linux 虚拟化环境里排障第一件事永远不是调参数也不是加资源而是先确认虚拟机到底有没有真正使用 KVM 加速。因为 KVM 和 QEMU 软件模拟之间的性能差距不是百分之二十三十的问题而是数量级的问题。本文就围绕这个判断把确认方法、常见原因、修复路径和长期预防一次说清楚。1. 虚拟机慢为什么第一步要先问“它真的是 KVM 吗”1.1 一个典型的“慢”现场先还原一个我遇到的场景。某台测试机起初在物理服务器上跑得很正常后来因为机房调整用备份镜像迁移到了另一台机器。迁移之后虚拟机里的 Rocky 10 开始出现明显的卡顿。打开终端窗口有延迟编译一个项目的时间比以前长了三倍查看系统监控时始终能看到一个 QEMU 进程的 CPU 占用很高。这时常见的排障思路是什么先看内存够不够再看磁盘 I/O然后逐个排查 Guest 内部的进程最后甚至会把压力归到网络或负载均衡上。但如果你在宿主机上用top看会发现占用 CPU 的是qemu-system-x86_64进程本身而这个进程正是虚拟机所有资源和指令的执行者。也就是说性能瓶颈极有可能发生在虚拟化层面而不是 Guest 内部。如果这时候不去确认虚拟化加速是否生效后面很多优化动作都是无效的。加 CPU、加内存、调节 I/O 调度可能都解决不了根本问题。因为问题的本质不是“资源不够”而是“指令执行方式从硬件加速退回到了软件翻译”。1.2 慢的本质KVM 和软件模拟差在哪儿要理解为什么必须先确认这一点得先搞清楚 KVM 和 QEMU 的关系。KVM 是 Linux 内核里的虚拟化模块它利用 CPU 的硬件虚拟化扩展Intel 的 VT-x 或 AMD 的 SVM把 Guest 中的大部分特权指令直接交给物理 CPU 执行。QEMU 则负责模拟设备、管理内存、处理 I/O 等但它本身在指令执行层面有两个模式当/dev/kvm存在并且 QEMU 以-accel kvm方式启动时Guest CPU 指令会尽可能直接跑在物理 CPU 上这叫硬件辅助虚拟化。当没有 KVM 加速时QEMU 会退回到 TCGTiny Code Generator纯软件模拟把 Guest 的二进制指令翻译成宿主机指令再执行。这种翻译过程有一个比较直观的表现CPU 会一直忙但实际进度很慢。用一个不太严谨但容易理解的类比KVM 加速有点像一个掌握同声传译能力的翻译说话人讲一句他几乎同步翻译一句而 TCG 则是先录下整段话再逐句查字典翻译过程中还要反复确认是否理解正确。翻译能力的差距直接体现在交流效率上。具体到虚拟机上普通工作负载在 TCG 模式下性能下降一两倍很正常某些 CPU 密集型的计算任务下降得更多。这不是“慢一点”而是“不可用”。所以虚拟机变慢时第一步先确认“是不是跑在 KVM 上”是整个排障流程的地基。2. 三种确认方式从宿主到 Guest从进程到日志确认一个虚拟机是否真的跑在 KVM 上比很多人想象中简单。不需要复杂工具只要按宿主、配置、Guest 三层来验证。2.1 宿主侧先看 /dev/kvm 和 QEMU 进程参数第一种方式是在宿主机上直接看虚拟机的实际运行参数。KVM 加速的前提是宿主机存在/dev/kvm设备节点并且内核已经加载了对应的 KVM 模块。# 查看 /dev/kvm 设备是否存在 ls -l /dev/kvm # 查看 KVM 内核模块是否加载 lsmod | grep kvm # 查看 CPU 是否支持虚拟化扩展物理机或已开启嵌套的虚拟机 grep -E vmx|svm /proc/cpuinfo正常情况下/dev/kvm应该是一个字符设备权限通常属于kvm组。lsmod会看到kvm_intel或kvm_amd模块以及kvm模块本身。接下来看 QEMU 进程是怎样启动的。如果你用的是 libvirt 管理虚拟机# 查看所有虚拟机列表 virsh list --all # 查看正在运行的 QEMU 进程的完整命令行 ps -ef | grep qemu-system重点关注命令行里有没有这些东西-machine accelkvm-cpu host或者在 QEMU 参数中出现accelkvm如果看到的是-accel tcg或者没有显式的kvm加速参数那就要高度怀疑这台虚拟机和 KVM 加速没有关系了。2.2 Guest 侧systemd-detect-virt 和 CPU 型号的真相在虚拟机内部验证是更直接的判断方式。Rocky 10 使用 systemd所以天然有一个命令可以用。systemd-detect-virt如果虚拟机确实跑在 KVM 加速上这条命令通常会输出kvm。如果输出的是qemu说明它运行在 QEMU 模拟环境里但不能确定是否硬件加速如果输出none那就是物理机或某些特殊虚拟化环境。再配合看 CPU 信息lscpu在 KVM 加速且 CPU 模式为host-passthrough或host-model的情况下Guest 里的 CPU 型号会和宿主机比较接近通常能看到真实 CPU 系列名。如果看到QEMU Virtual CPU version 2.5这类名字多半是用了 QEMU 内置的虚拟 CPU 模型性能会低于真实 CPU。虽然这并不代表一定没有 KVM 加速但至少说明配置没有把加速能力充分发挥出来。2.3 配置侧libvirt XML 里的虚拟化类型如果你使用virsh管理虚拟机配置信息保存在 domain XML 里。里面最关键的一行是domain标签的type属性。# 查看虚拟机的 XML 配置 virsh dumpxml 虚拟机的名字正常情况下KVM 加速配置应该是domain typekvm如果显示是domain typeqemu那就说明 libvirt 会默认使用纯 QEMU 模式启动虚拟机也就是 TCG 软件模拟。这是最容易识别的信号之一。同样重要的是 XML 里的 CPU 配置cpu modehost-passthrough/或cpu modehost-model/如果看到的是cpu modecustom matchexact model fallbackallowqemu64/model /cpu那么即使已经用了 KVM 加速CPU 指令集也会被限制在一个非常保守的兼容模型上部分对指令集敏感的工作负载照样会变慢。3. 没有跑在 KVM 上的常见原因和修复路径确认了“没有真正跑在 KVM 上”之后接下来就要弄清楚为什么。根据经验最常见的原因集中在硬件、内核模块、权限和配置这四个层面。3.1 硬件虚拟化没有打开或不可用KVM 必须依赖 CPU 硬件虚拟化扩展。如果宿主机是物理机要先确认 BIOS/UEFI 里是否开启了 Intel VT-x 或 AMD-V。不同厂商的主板菜单不一样但关键词通常有Intel Virtualization Technology、SVM Mode等。确认方法是在宿主机上执行grep -E vmx|svm /proc/cpuinfo有输出说明 CPU 支持且当前环境可用。没有输出就需要进 BIOS 开启开启后重启再检查。还有一种情况容易被忽略宿主机本身也是一个虚拟机。比如在这台虚拟机里再跑 Rocky 10 虚拟机而底层没有开启嵌套虚拟化那么上层 Guest 自然就用不了 KVM。这种场景下要先去底层宿主确认嵌套虚拟化参数而不是在 Guest 里反复折腾。3.2 KVM 模块没加载、被版本升级覆盖如果 CPU 支持虚拟化但执行lsmod | grep kvm没有输出说明内核模块没有加载。可以先手动加载再确认# Intel CPU modprobe kvm_intel # AMD CPU modprobe kvm_amd加载成功后再次执行lsmod | grep kvm和ls -l /dev/kvm。如果加载时报错查看内核日志dmesg | grep -i kvm常见报错信息包括 “module is already loaded” 或 “Operation not supported” 等。其中Operation not supported往往说明当前环境没有可用硬件虚拟化能力。在 Rocky 10 这类系统上内核一般会携带 KVM 模块但不会保证一定会自动加载。为了避免重启后回到“无加速”状态可以把对应的模块写入自动加载配置# /etc/modules-load.d/kvm.conf kvm kvm_intel等下次机器重启后再检查模块是否自动加载。3.3 权限和嵌套虚拟化配置有时候/dev/kvm设备存在但当前运行虚拟机的用户没有访问权限导致 libvirt 在启动时无法使用 KVM 加速。这种问题通常表现为创建虚拟机失败或者 libvirt 自动回退到 QEMU 模式。解决方法是把运行虚拟机的用户加入kvm组usermod -aG kvm your-user新添加的组成员关系需要重新登录才能生效。如果使用 root 运行 libvirtd则需要确认/etc/libvirt/qemu.conf中配置的user和group是否有权限访问/dev/kvm。嵌套虚拟化场景还要额外检查# 查看是否允许嵌套 cat /sys/module/kvm_intel/parameters/nested输出为1、Y或y表示允许。如果为0需要卸载模块后重新加载并设置嵌套参数modprobe -r kvm_intel modprobe kvm_intel nested1不过在正式环境里我更建议在引导配置中固定这个参数避免每次手工处理。3.4 修复后如何验证修复不能只用一条命令确认。我习惯按这个顺序走一遍宿主机检查grep -E vmx|svm /proc/cpuinfo是否正常。检查lsmod | grep kvm是否已经加载。检查ls -l /dev/kvm是否存在。启动一台测试虚拟机。在宿主机上用ps -ef | grep qemu-system查看 QEMU 参数是否包含accelkvm。进入 Guest 执行systemd-detect-virt看输出是否为kvm。这里有一个容易被忽略的建议不要一次性把所有虚拟机都启动。先挑一台测试机验证确认加速已经生效后再批量恢复业务虚拟机。否则如果配置本身有问题可能所有虚拟机都会以错误的模式运行很长时间。4. 一套可复用的“KVM 加速自检”流程前面这些命令每次逐步执行也能用但排障最怕的是漏掉某一层。把检查步骤固化成一个脚本可以明显减少人为遗漏。4.1 快速检查脚本设计思路脚本只需要做“检查”和“提示”不需要直接修改系统。原则是尽早暴露出问题而不是自动修复。下面是一个适合作为参考的脚本结构#!/usr/bin/env bash echo 1. CPU 硬件虚拟化扩展 if grep -E vmx|svm /proc/cpuinfo /dev/null; then echo OK: CPU 支持虚拟化扩展 else echo FAIL: 未检测到 vmx/svm请在 BIOS/固件中开启或确认嵌套虚拟化已开启 fi echo echo 2. KVM 内核模块 if lsmod | grep -q ^kvm; then lsmod | grep ^kvm else echo WARN: 没有检测到 KVM 模块 fi echo echo 3. /dev/kvm 设备 if [ -e /dev/kvm ]; then ls -l /dev/kvm else echo FAIL: /dev/kvm 不存在 fi echo echo 4. QEMU 进程参数 if pgrep -f qemu-system /dev/null; then ps -ef | grep qemu-system | grep -v grep || true else echo INFO: 当前没有正在运行的 QEMU 进程 fi脚本本身不复杂但它能在第一时间区分出问题在哪一层。实际使用中可以根据业务环境补充“检查 libvirt XML”的步骤比如用virsh dumpxml提取domain的type属性再判断是不是kvm。4.2 纳入日常健康检查单次执行脚本只是排障长期价值在于把它放进日常巡检或监控系统。现在很多团队已经有周期监控但监控位置往往停留在“虚拟机能不能通”、“磁盘空间是否够用”这一层。更建议至少把以下两个指标纳入检查宿主机上是否存在应该运行但退化为 TCG 模式的虚拟机。/dev/kvm 设备是否从可用变成不可用。实现思路不算复杂可以定期跑脚本如果检测到“应该使用 KVM 加速但进程参数没有包含 accelkvm”的情况就把警告发到告警群里。这一步真正能避免的是“偷偷回退”的坑比如某个虚拟机从备份恢复后配置被改写成了 qemu 模式业务还在跑只是慢得离谱。4.3 边界哪些情况确认是 KVM 但还是慢必须说清楚确认 KVM 加速只是排障的第一步并不等于性能问题一定解决。现实中还有一种情况确实跑在 KVM 上了但虚拟机和宿主机两层配置都不合理。比如宿主机没有配置 CPU pinning虚拟机的 vCPU 频繁在不同物理核之间跳动缓存亲和性变差比如虚拟机的磁盘设备用的是纯 IDE 模拟而不是 virtio比如 Guest 内的 virtio 驱动没有安装完整导致网络和磁盘吞吐上不去再比如物理机的 NUMA 拓扑没有被 vCPU 内存亲和性利用好。这些优化方向和“确认 KVM 加速”并不冲突恰恰相反只有先确认加速引擎已经点火后面的优化才有意义。否则在 TCG 模式下调 I/O 队列长度效果自然很差因为瓶颈根本不在 I/O 配置上。5. 落到长期维护不要只做一次确认很多虚拟机性能问题最麻烦的不是当次排障而是“今天修好了下周又坏了”。KVM 加速失效这件事很容易在几次看似无关的操作后悄悄发生。5.1 升级后回退陷阱Rocky 10 作为一个 RHEL 系发行版内核和虚拟化相关组件都会持续更新。历史上并不缺少这种情况系统更新后需要重启重启后发现/dev/kvm没生成或者 KVM 模块没有加载。如果你没有配置/etc/modules-load.d/kvm.conf也没有把检查命令放进运维手册里那么一次内核升级就可能让所有虚拟机重新进入软件模拟模式。而且如果使用的是 libvirt 默认的typeqemu配置可能连报错都不会有业务照样启动只是性能崩了。5.2 迁移/备份恢复后配置漂移工程项目里最常见的问题是虚拟机从 VMware 或 Hyper-V 迁移过来或从备份镜像恢复后domain XML 发生了变化。这类跨虚拟化平台的迁移很容易把domain typekvm改成domain typeqemu或把 CPU 模式改成兼容性最好的 qemu64。从另一个角度看这其实是迁移工具在“降低兼容性风险”目的是让镜像能启动。但如果迁移后不加确认它就会成为性能隐患。备份恢复也一样。如果你用virsh dumpxml保存过 XML恢复时要检查保存的 XML 是否被修改过如果你使用的管理平台自动生成 XML也要防止平台默认模板覆盖原有配置。5.3 一个简单的清单建议把下列检查项保存成运维清单每次迁移、升级、恢复后跑一遍检查项期望结果检查方式CPU 硬件虚拟化扩展宿主机/proc/cpuinfo含 vmx 或 svmgrep -E vmx|svm /proc/cpuinfoKVM 内核模块lsmod包含 kvm 和 kvm_intel/kvm_amdlsmod | grep kvm/dev/kvm 设备文件存在且可访问ls -l /dev/kvmlibvirt 域类型domain type 为 kvmvirsh dumpxml vm | grep domainQEMU 进程参数包含 accelkvm 或 -machine accelkvmps -ef | grep qemu-systemGuest 虚拟化检测输出 kvmsystemd-detect-virtCPU 模型使用 host-passthrough 或 host-modelvirsh dumpxml vm | grep -A5 cpu这个清单看起来很简单但每一步都在回答“虚拟机的指令到底由谁执行”这个问题。指令执行方式正确性能优化才有讨论的基础指令执行方式不对再复杂的参数调优都是在错误的地基上盖楼。下次再遇到 Rocky 10 虚拟机变慢先别急着加 vCPU也别急着重装系统。花两分钟确认它真的跑在 KVM 上这个动作成本极低但往往能帮你省下半天甚至一天的排障时间。虚拟化性能是一条很长的链路从 CPU 指令执行到设备模拟再到 Guest 驱动每一环都有优化空间。而这条链路的第一环永远是确认加速引擎已经点火。