kvm虚拟机卡顿怎么办?先改三处配置:CPU模式换成host-passthrough、磁盘总线换成virtio、关掉内存气球驱动,绝大多数卡顿问题当场就能缓解。剩下的事情就是顺着性能链路逐层排查,下面按实际操作顺序展开,每一步都有可验证的命令和效果,照着做就行。
先分清是谁的锅:kvm虚拟机卡顿排查宿主还是客户机
看宿主机的负载和st值
卡顿发生时,先别急着在虚拟机里折腾,登录宿主机执行top,观察三列:wa(IO等待)、si(交换分区写入)、st(steal time,被其他虚拟机偷走的时间)。st值持续走高,说明物理CPU资源被别的虚拟机抢占;wa高说明磁盘在拖后腿;si高说明宿主机内存不够,正在频繁换页。
在虚拟机里执行同样的top对照一下,如果虚拟机内负载不高但操作明显慢半拍,问题大概率不在虚拟机本身,而在宿主机层面。
用实际场景给卡顿定性
在虚拟机里跑一条磁盘写入测试:
time dd if=/dev/zero of=/tmp/test bs=1M count=1024
再在物理机上跑同样的命令,对比耗时,写入速度差出两三倍以上,先处理磁盘路径;如果结果接近,继续查CPU和内存配置,这样一轮操作下来,基本能确定卡顿的大方向。
CPU模式选不对,kvm虚拟机卡顿是必然的
把CPU模式改成host-passthrough
KVM默认的qemu64模型为了兼容性只模拟了最基础的指令集,AVX、SSE4.2这些高性能指令全部缺失,虚拟机里做编译、转码、数据库聚合运算时,CPU只能通过模拟路径执行,性能差距非常明显。
你能直接感受到的迹象:cat /proc/cpuinfo里的flags比物理机少一大截,跑分软件数字难看,操作反馈像隔了一层,解决办法是修改虚拟机XML:
virsh edit vm-name
找到<cpu>段落,改成:
<cpu mode='host-passthrough' check='none'/>
保存后重启虚拟机,行业共识认为,host-passthrough能把QEMU模拟造成的CPU性能损耗压到极低,接近物理机水平。
NUMA拓扑和vCPU绑定
宿主机开了NUMA时,虚拟机内存可能被分配到远端节点,跨节点访问内存会拉高延迟,用numastat -c查看内存访问命中率,再用virsh vcpupin把vCPU绑到同一NUMA节点对应的物理核上,比如物理机上0-7号核属于node0,就把虚拟机的vCPU绑过去:
virsh vcpupin vm-name 0 0
virsh vcpupin vm-name 1 1
vCPU数量也要克制,给虚拟机分配超过物理核心数的vCPU,在超线程环境下更可能互相争抢执行单元,很多“开了很多核反而变卡”的现象都源于此。
磁盘IO是重灾区:kvm虚拟机性能调优从存储开始
qcow2和raw的选择
创建虚拟机时默认用qcow2,因为它支持快照、压缩,省空间,但这个格式每写一个扇区都要处理写时复制逻辑,数据路径比raw长不少,负载升高时,快照链越长,卡顿越明显。
| 对比项 | qcow2 | raw |
|---|---|---|
| 快照 | 支持 | 不支持 |
| 写入开销 | 较高 | 低 |
| 空间占用 | 按需增长 | 一次性分配 |
| 适合场景 | 桌面系统、频繁重装 | 数据库、日志、高IO业务 |
业务负载较高的话,可以考虑把磁盘转换成raw:
qemu-img convert -f qcow2 -O raw vm.qcow2 vm.raw
如果舍不得放弃快照能力,也可以保留qcow2,但要确保快照链不长,并及时合并过期快照。
磁盘总线改用virtio
虚拟机XML里磁盘默认的ide总线模拟了老式IDE控制器,CPU参与度极高,吞吐量有限,改成virtio之后,虚拟磁盘走半虚拟化通道,性能提升非常明显。
修改<disk>段落:
<target dev='vda' bus='virtio'/>
同时配合<driver name='qemu' type='raw' cache='writeback' io='native'/>,io='native'让QEMU直接走Linux原生AIO,减少一层拷贝,业内专家指出,cache=unsafe模式虽然测试环境下跑分好看,但生产环境断电会丢数据,不要为了流畅度牺牲耐久性。
宿主机磁盘别拖后腿
虚拟机层调完,还要看宿主机磁盘本身扛不扛得住,执行iostat -x 1观察util,长期贴到100%说明物理盘已经饱和,加缓存盘或换NVMe才是真正解法,另外检查宿主机crontab里有没有定时任务恰好在卡顿时间段触发备份、快照合并、压缩日志,这些后台操作会在你毫无察觉时抢走整个磁盘的带宽。
kvm装windows卡顿怎么办?先检查virtio驱动
Windows虚拟机的驱动陷阱
Windows虚拟机如果没装virtio驱动,磁盘和网卡都会回退到IDE和e1000模拟模式,Windows本身对这两种老设备的驱动兼容性没问题,坏就坏在模拟路径上每个IO都要经过QEMU翻译,效率不高。
装驱动的顺序很重要,否则可能出现开机蓝屏,先在IDE模式下挂载virtio-win.iso,进入设备管理器手动更新驱动,把磁盘、网卡、内存气球驱动都装上,再关机把XML里的总线改成virtio,全链路virtio驱动正常,Windows虚拟机的流畅度才算过关。
鼠标漂移、点不准,也是Windows虚拟机常见卡顿表现,把USB控制器配置成usb-tablet:
<input type='tablet' bus='usb'/>
这样鼠标坐标由虚拟机主动报告,指针不再飘。
内存气球驱动影响不可忽视
balloon驱动允许宿主机动态回收虚拟机内存,回收逻辑激进的时候,虚拟机内部只能压缩内存页来凑空间,表现就是操作不跟手、鼠标一顿一顿。
临时验证方法:给虚拟机一个固定内存,先去掉balloon:
<memballoon model='none'/>
重启后如果卡顿消失,说明balloon回收策略和业务负载不匹配,这里有个常见场景:宿主机内存吃紧时,balloon会优先回收“看起来空闲”的内存,但很多应用的空闲内存其实是缓存,回收后反而触发更高开销的重新读取,把balloon模型关掉,让虚拟机内存不再被动态回收,卡顿立减。
kvm虚拟机和vmware区别掉头看,性能排查思路要换
VMware的思路不一定适合KVM
kvm虚拟机和vmware区别不只是名字和授权方式,默认配置的性能下限差异很大,VMware装完vmtools,驱动、内存回收都对用户透明处理好了,性能基线稳定,KVM默认裸奔,不调就能跑的虚拟机只在极轻负载下成立,生产环境的流畅度全靠手动调优换回来。
所以遇到卡顿,从VMware迁移过来的运维容易走弯路:装好驱动还卡就怀疑宿主机,在KVM里这个顺序可能适得其反,KVM的正确顺序是先看CPU模式,再看磁盘总线,最后才查驱动,从kvm虚拟化价格角度算,自建KVM比VMware省掉一大块授权费用,但那些省下来的钱实际变成运维排查时间和调优成本,买台云主机前要想清楚这笔账。
网络多队列同样不能偷懒
单队列网卡在高并发小包场景下,同一个vCPU既要收包又要处理中断,处理不过来就会出现“延迟一下,然后突然爆发”的卡顿感,把virtio网卡设为多队列:
<driver name='vhost' queues='4'/>
配合宿主机上ethtool -L eth0 combined 4开启物理网卡多队列,收包中断分散到多个vCPU,网络卡顿基本消失,这在跑大流量业务时改善非常直观。
kvm生产环境性能排查清单
15分钟定位卡顿源头
按这个顺序走一遍,kvm生产环境卡顿排查不会漏掉主要因素:
- 宿主机
top,观察st、wa、si三项,排除资源争抢。 - 虚拟机里
grep flags /proc/cpuinfo,确认有avx2和sse4_2。 lsblk -t确认总线是virtio。free -g看内存是否被回收。ethtool -l eth0看网卡队列数。
任何一项不符预期,按上文对应模块调整。
按卡顿时间点反推
卡顿发生在开机阶段,大概率是qcow2快照链太长,启动时IO风暴集中爆发,合并快照或改raw就好。
卡顿出现在宿主机固定任务的时间点,查cron里有没有备份、快照合并、磁盘扫描,调整任务顺序避开业务高峰。
卡顿持续且虚拟机重启后短暂恢复,考虑KSM内存合并带来的波动,临时关掉KSM:
echo 0 > /sys/kernel/mm/ksm/run
这是当前虚拟机最直接的验证方式,长期关闭需要写入systemd服务,注意KSM关闭会让宿主机内存占用上升,做好容量评估。
云主机场景下这些排查可能受限于权限和宿主机隔离,部分操作无法生效,那就考虑换用配置更高的实例规格,或者联系厂商技术支持确认资源争抢情况。
kvm虚拟机卡顿常见问题解答
kvm虚拟机卡顿怎么排查最快最准
按顺序执行三条命令:宿主机top看st值,虚拟机里cat /proc/cpuinfo看CPU模式,lsblk -t看磁盘总线类型,三者中任意一项异常,直接对应修复即可,全部正常再去看内存balloon设置和网络队列数。
kvm装windows卡顿一定是因为显卡吗
多数情况下不是显卡问题,磁盘驱动没装全才是主因,Windows在缺少virtio驱动时会使用IDE和e1000模拟设备,每一项都在拖慢存储和网络链路,系统响应自然笨重,先安装virtio-win驱动包全部组件,再把XML里的disk和interface改成virtio模式,图形体验会明显好转,显卡本身的模拟性能反而影响很小。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/621856.html





