KVM虚拟机数量达到200台后,如何联动监控CPU、内存与I/O性能?
200台KVM虚拟机是否能够稳定运行,不能只看宿主机CPU利用率。CPU使用率不高时,内存回收、交换、存储队列或单台虚拟机的突发负载,仍然可能让业务响应时间明显变长。正确的判断方式是把宿主机、虚拟机和业务响应放在同一时间轴内,联动观察CPU调度、内存压力、I/O延迟、队列深度、吞吐量、并发数和错误率。

在单台2U香港服务器上运行200台虚拟机时,应先建立基线,再按50台、100台、150台、200台逐级增加并发负载,分别记录稳定负载和突发负载下的p95、p99指标。最终容量取CPU、内存、I/O和响应时间几个结果中的最小值,而不是取某一项看起来最宽裕的资源。200台虚拟机可以是配置层面的数量目标,但能否长期承载,取决于这200台虚拟机的实际工作集、CPU峰值和I/O访问模式。
先建立统一的观察窗口
2U不是性能参数,先确认可用资源
“2U”只表示服务器机箱高度,不能直接推导出可运行多少台虚拟机。测试前应记录以下信息:
- 物理CPU型号、物理核心数、逻辑线程数和CPU频率策略;
- 可用内存容量,以及预留给宿主机、KVM进程和基础服务的内存;
- 存储设备类型、RAID或存储池结构、缓存模式和文件系统;
- Linux内核、KVM、QEMU、libvirt版本;
- 200台虚拟机的vCPU数、内存配置、虚拟磁盘数量和虚拟网卡数量;
- 虚拟机是否启用内存气球、客户机代理、磁盘缓存和I/O限速;
- 每类业务的并发请求、吞吐量、响应时间目标和错误率目标。
没有这些信息时,只能讨论容量估算方法,不能把“200台”直接判断为可承载或不可承载。
所有指标必须使用同一时间范围
建议至少保留三种时间粒度:
| 时间粒度 | 主要用途 | 适合观察的现象 |
|---|---|---|
| 1秒或5秒 | 捕捉瞬时尖峰 | CPU突发、I/O队列、网络丢包、响应时间尖峰 |
| 1分钟 | 判断短时稳定性 | 资源利用率、吞吐、错误率、虚拟机批量抖动 |
| 5分钟或15分钟 | 评估容量余量 | 内存持续回收、交换、缓存耗尽、增长趋势 |
一次测试中,CPU、内存、I/O和应用响应时间必须使用相同的起止时间。不能拿某分钟的CPU平均值,去解释另一分钟的I/O峰值。
建议把每个采样点都关联一个统一时间戳,至少保存以下字段:
- 宿主机CPU使用率、iowait、运行队列;
- 虚拟机vCPU使用率、steal时间或等待调度时间;
- 宿主机可用内存、内存压力、swap进出量;
- 虚拟机实际工作集、major page fault和内存回收情况;
- 存储读写IOPS、吞吐量、await、队列深度;
- 虚拟机块设备读写字节数和读写请求数;
- 网络吞吐、错误、丢包、重传;
- 应用并发数、QPS或事务吞吐、p50/p95/p99响应时间、错误率。
设计200台虚拟机的压测环境
用分阶段并发代替一次性启动
如果直接让200台虚拟机同时产生峰值负载,最终只能知道“系统变慢了”,却很难确定从哪一个阶段开始变慢。更适合的测试顺序如下:

- 先启动200台虚拟机,但全部处于空闲或低负载状态,记录30分钟基线。
- 逐步让50台、100台、150台和200台虚拟机进入稳定业务负载。
- 每个阶段至少保持10至15分钟,等待CPU调度、文件缓存和内存回收趋于稳定。
- 在200台稳定负载后增加短时突发,例如将并发请求提高到稳定值的1.5倍,持续5至10分钟。
- 停止突发负载,继续观察恢复时间,确认队列、swap和响应时间是否回到基线附近。
- 重复至少两到三轮,区分偶然尖峰和稳定性问题。
负载应尽量接近实际业务组合,而不是让200台虚拟机执行完全相同的压力程序。例如可以将测试对象划分为轻量服务、CPU型服务、内存型服务和I/O型服务。下面是一组用于说明方法的示例,不代表某台具体服务器的实际业务比例:
| 虚拟机类型 | 数量 | 主要观察指标 |
|---|---|---|
| 轻量服务 | 120台 | 并发数、响应时间、网络吞吐 |
| CPU型服务 | 50台 | vCPU利用率、steal、运行队列 |
| 内存型服务 | 20台 | 工作集、内存压力、major fault |
| I/O型服务 | 10台 | IOPS、await、队列深度、写入延迟 |
如果真实环境中I/O型虚拟机比例更高,就应按真实比例测试。虚拟机数量相同,工作负载不同,容量结果可能完全不同。
记录测试前的版本和配置
测试开始前可先确认宿主机和虚拟化管理工具版本。以下命令适用于常见Linux宿主机,属于只读查询:
uname -a
command -v virsh
command -v mpstat
command -v vmstat
command -v iostat
virsh version
virsh list --all
如果mpstat或iostat不存在,不要直接猜测安装包名称,应根据发行版的软件仓库安装对应的sysstat工具,并在安装后重新确认版本。测试中不建议临时修改CPU调度、磁盘缓存或内存超分参数,否则不同轮次之间不再具备可比性。
I/O压力测试应使用专门的测试数据集或可丢弃的测试文件,不能对生产磁盘直接执行原始设备写入。涉及写入的测试要先确认备份、数据范围和回滚方式;如果使用虚拟机内部的压力工具,应限制单台虚拟机的负载,并按批次逐渐增加,避免一条命令瞬间压满共享存储。
同一时间轴内联动采集CPU、内存和I/O
宿主机层面的基础采集
在压测阶段,可以分别保存CPU、内存、I/O和网络数据。下面命令主要用于采样,不会修改系统配置:
mpstat -P ALL 1 60 > /var/tmp/mpstat-$(date +%Y%m%d-%H%M%S).log
vmstat 1 60 > /var/tmp/vmstat-$(date +%Y%m%d-%H%M%S).log
iostat -xmd 1 60 > /var/tmp/iostat-$(date +%Y%m%d-%H%M%S).log
sar -n DEV 1 60 > /var/tmp/sar-net-$(date +%Y%m%d-%H%M%S).log
同时可以查看Linux压力停顿信息:
cat /proc/pressure/cpu
cat /proc/pressure/memory
cat /proc/pressure/io
这些文件中的some表示部分任务因对应资源而等待,full表示所有可运行任务都受到影响。单看CPU百分比时,可能看不出短时间内任务排队;PSI可以帮助确认是否真的发生了资源等待。
对正在运行的虚拟机,可以用libvirt获取累计CPU、内存和块设备统计。由于不同libvirt版本支持的字段可能不同,先查看帮助信息:
virsh domstats --help
在常见版本中,可以按虚拟机逐台查询:
for vm in $(virsh list --name --state-running); do
printf '\n[%s] %s\n' "$(date --iso-8601=seconds)" "$vm"
virsh domstats --vcpu --balloon --block --cpu-total "$vm"
done
200台虚拟机每10秒全部查询一次,可能增加管理面开销。实际采集时可先使用30秒或60秒间隔,压测期间再根据采集开销调整。domstats中的CPU时间、读写字节数和读写请求数通常是累计值,需要用相邻两次采样的差值除以时间间隔,才能得到这一时间段的CPU占用、IOPS或吞吐量。
关键指标不能脱离上下文解释
| 指标 | 需要同时观察的指标 | 可能说明的问题 |
|---|---|---|
| 宿主机CPU利用率 | run queue、guest steal、响应时间 | CPU是否真的成为调度瓶颈 |
| CPU iowait | await、I/O队列、存储吞吐 | 等待磁盘还是CPU不足 |
| 内存使用率 | available、PSI、swap、major fault | 是缓存占用还是实际内存压力 |
| I/O利用率 | await、aqu-sz、读写比例、响应时间 | 设备是否接近延迟边界 |
| 虚拟机steal | 宿主机运行队列、其他虚拟机负载 | 虚拟机是否等待物理CPU |
| 应用p99响应时间 | QPS、错误率、网络重传 | 性能下降是否已经影响业务 |
| 网络吞吐 | 丢包、错误、重传、CPU软中断 | 网络问题还是计算、I/O问题 |
宿主机free较低不一定代表内存不足,因为文件缓存也会占用内存。相反,即使仍有一定可用内存,只要memory PSI、swap进出和major fault持续上升,也可能已经出现实际内存压力。
虚拟机内部指标要与宿主机指标配对
宿主机只能准确看到虚拟机分配了多少内存、消耗了多少虚拟CPU时间以及虚拟块设备产生了多少I/O,无法仅凭宿主机数据判断虚拟机内部应用的工作集和进程级内存情况。
因此,至少要在每类虚拟机中选取代表样本,采集:
mpstat中的用户态、内核态、iowait和steal;vmstat中的运行队列、swap进出和内存回收;iostat中的虚拟磁盘await、读写请求和吞吐;- 应用自身的并发连接、请求数、响应时间和错误率。
在KVM环境中,客户机的steal持续升高,通常说明虚拟CPU没有及时获得物理CPU时间。但steal不能单独作为结论,还要对照宿主机运行队列和其他虚拟机的CPU负载。如果宿主机CPU利用率不高而某一虚拟机steal很高,还需要检查CPU亲和性、vCPU拓扑、调度限制或采样方式。
用联动关系判断真正的瓶颈
下面数据是用于说明判断过程的模拟监控数据,不代表具体服务器的实测结果。重点不是某个绝对数值,而是多个指标在同一时间窗口内如何变化。

| 时间窗口 | 宿主机CPU | 内存PSI some | swap写入 | 存储p99 await | I/O队列 | 应用p99 | 错误率 |
|---|---|---|---|---|---|---|---|
| 200台低负载基线 | 42% | 0.2% | 0 | 2ms | 0.5 | 85ms | 0.05% |
| 200台稳定负载 | 68% | 0.8% | 0 | 5ms | 2.1 | 150ms | 0.10% |
| CPU突发阶段 | 86% | 1.0% | 0 | 6ms | 2.5 | 420ms | 0.45% |
| 内存压力阶段 | 64% | 12% | 45MB/s | 28ms | 18 | 980ms | 1.30% |
| I/O突发阶段 | 57% | 1.2% | 0 | 35ms | 24 | 760ms | 0.80% |
CPU利用率上升,同时响应时间和steal上升
如果CPU突发阶段出现以下组合:
- 宿主机CPU从68%升至86%;
- 宿主机运行队列持续增长;
- 多台虚拟机的steal从1%升至6%;
- 存储await基本不变;
- 应用吞吐不再随并发线性增长;
- p95、p99响应时间和错误率同时上升;
这更接近CPU调度瓶颈,而不是存储问题。此时应查看是所有虚拟机一起变慢,还是少数高负载虚拟机占用了CPU。
如果只有少数虚拟机持续消耗CPU,可以先按业务类型统计每台虚拟机的p95 CPU需求,设置合理的CPU权重或上限,并重新测试。盲目增加vCPU数量,可能让调度队列更长,不能保证响应时间改善。
内存压力上升,同时I/O变慢
内存压力经常会伪装成I/O瓶颈。典型组合是:
- 宿主机CPU没有达到最高水平;
memory PSI持续上升;- swap写入或读取出现持续流量;
- 存储await和I/O队列同步增长;
- 应用p99响应时间明显变长;
- 停止负载后,内存回收和I/O队列需要一段时间才能恢复。
这时不能简单得出“磁盘性能不够”的结论。交换、内存回收和文件缓存失效都可能把内存压力转化为磁盘访问。应先确认虚拟机实际工作集、宿主机可用内存和swap活动,再单独做一轮内存容量测试。
内存气球和内存合并可以提高资源利用率,但会增加回收或扫描开销,不能把配置上的超分内存直接当作可用物理内存。只要压力测试中出现持续swap或明显major fault,就应把内存余量重新纳入容量上限。
CPU不高,但I/O队列和响应时间上升
如果出现以下组合:
- 宿主机CPU仅为50%至65%;
- 内存PSI和swap基本稳定;
- 存储await从数毫秒升至几十毫秒;
aqu-sz或I/O队列持续增加;- 应用p99响应时间上升;
- 读写吞吐接近测试得到的服务能力上限;
瓶颈更可能在共享存储,而不是CPU。尤其是多台虚拟机同时进行随机写入时,平均吞吐可能仍然看起来不高,但尾延迟和队列已经失控。
%util可以作为参考,但不能单独作为NVMe或多队列存储的容量结论。应同时看读写延迟、队列深度、读写比例和应用响应时间。对于I/O型虚拟机,还应统计单台虚拟机的读写请求,确认是否存在一个或少数几个实例把共享队列占满。
网络指标异常时,先排除替代解释
如果应用响应时间上升,同时CPU、内存和I/O均正常,应检查:
- 网卡错误和丢包;
- TCP重传;
- 虚拟网卡队列;
- 宿主机软中断是否集中在少数CPU;
- 测试探针与业务服务之间的路径是否发生变化。
网络吞吐高不等于网络出现瓶颈,网络吞吐低也不一定代表网络正常。必须把网络错误、重传和应用响应时间放在同一时间窗口分析。固定测试节点、固定请求路径和固定数据集,有助于避免把外部网络波动误认为服务器资源问题。
按资源类型估算超分边界
CPU:先算实际需求,再看vCPU比例
CPU超分比例可以用来描述配置,但不能直接代表性能:
CPU超分比例 = 所有虚拟机vCPU总数 ÷ 宿主机物理核心数
例如,宿主机有32个物理核心,200台虚拟机每台配置1个vCPU,则:
200 ÷ 32 = 6.25
这表示配置层面的vCPU与物理核心比例为6.25∶1,不表示这台服务器能够稳定承载6.25倍的持续CPU负载。如果每台虚拟机配置2个vCPU,比例会变成12.5∶1,但真实CPU需求仍取决于每台虚拟机的工作负载。
更实用的计算方式是估算每台虚拟机在目标时间窗口内的CPU需求:
总CPU需求 = 各虚拟机“vCPU数量 × 实际忙碌比例”的总和
例如某台1 vCPU虚拟机在稳定阶段平均占用0.04个物理核心,200台的稳定需求约为8个核心;如果突发阶段平均占用0.18个核心,总需求就会达到36个核心,已经超过32个物理核心,即使平时CPU利用率很低,也无法承受所有虚拟机同时突发。
容量估算还应保留宿主机和增长余量:
可安全使用的CPU = 物理核心数 × 目标利用率 - 宿主机固定开销
以32个物理核心、目标利用率70%、宿主机固定开销约2.5个核心为例:
32 × 70% - 2.5 = 19.9个核心
如果200台虚拟机在稳定负载下的聚合p95需求为15.8个核心,理论余量约为4.1个核心,余量比例约为20.6%。但如果突发阶段需求达到21.5个核心,就已经超过19.9个核心的安全使用线。此时可以说稳定负载尚有空间,但不能把200台虚拟机的突发峰值判定为安全。
CPU测试应同时记录以下结果:
- 聚合CPU利用率的p95和p99;
- 物理核心运行队列;
- 虚拟机steal的p95和最大值;
- 稳定负载下的吞吐增长率;
- 并发增加后响应时间是否出现拐点;
- 突发结束后队列和响应时间的恢复时间。
内存:以实际工作集而不是配置内存为核心
虚拟机配置内存总量只是上限,不等于实际使用量。200台虚拟机每台配置1GB,总配置内存为200GB,但如果实际工作集只有每台400MB,和每台900MB时的容量结果完全不同。
可以使用以下估算方式:
可安全使用的内存 = 物理内存 × 目标使用比例 - 宿主机与KVM预留
假设物理内存为256GB,内存目标使用比例为80%,宿主机及基础服务预留24GB:
256GB × 80% - 24GB = 180.8GB
如果200台虚拟机在稳定业务下的工作集p95合计为164GB,则理论余量约为16.8GB。但这只有约9.3%的安全容量,面对业务增长、缓存变化或批量重启后的同时预热,空间可能不足。
内存判定至少需要结合:
- 宿主机
MemAvailable而不是只看used; memory PSI的some和full;- swap读写是否持续;
- 虚拟机内部major page fault;
- 工作集是否随并发线性增长;
- 文件缓存回收后应用响应时间是否恶化;
- 大量虚拟机同时启动时的内存峰值。
如果内存配置超分,必须单独测试低负载、稳定负载、内存突发和虚拟机批量启动四种场景。日常低负载不发生swap,不代表200台虚拟机同时重启或缓存预热时也不会发生内存争用。
I/O:用延迟拐点确定可用容量
I/O容量不应只用“最大读写速度”衡量。对于虚拟机,以下指标通常更有参考价值:
- 读IOPS和写IOPS;
- 读吞吐和写吞吐;
- 平均await、p95 await和p99 await;
- 队列深度;
- 随机读写比例;
- 单台虚拟机的I/O占比;
- 应用事务响应时间和超时率。
可先通过分阶段测试得到一组曲线。例如:
| 混合I/O负载 | 存储p99延迟 | 队列深度 | 应用p99响应时间 | 解释 |
|---|---|---|---|---|
| 20,000 IOPS | 3ms | 1.2 | 110ms | 运行平稳 |
| 30,000 IOPS | 6ms | 3.0 | 160ms | 可作为稳定工作区间 |
| 40,000 IOPS | 18ms | 9.5 | 390ms | 开始出现尾延迟 |
| 50,000 IOPS | 42ms | 24.0 | 900ms | 队列持续堆积 |
如果30,000 IOPS时延迟仍稳定,40,000 IOPS开始出现明显尾延迟,那么生产容量不宜直接取50,000 IOPS。可以将延迟尚未明显拐升的区间作为运行区间,再根据增长计划保留15%至30%的余量。
I/O队列在短时突发时增长并不一定表示失败,关键要看突发结束后是否能恢复。如果队列在负载停止后仍持续增长,说明到达速率已经超过存储服务速率;如果几分钟内回落,说明系统仍有恢复能力,但需要确认恢复时间是否满足业务目标。
用最小余量决定还能增加多少台虚拟机
当CPU、内存和I/O都完成测试后,可以把新增虚拟机数量分别换算成资源余量:
可新增数量 = min(CPU余量 ÷ 单台CPU需求,内存余量 ÷ 单台内存需求,I/O余量 ÷ 单台I/O需求)
下面是一组示例计算:
- CPU余量:4.1个核心;
- 内存余量:16.8GiB;
- I/O余量:3,500 IOPS;
- 新增一台同类型虚拟机的CPU p95需求:0.018个核心;
- 新增一台虚拟机的工作集:90MiB;
- 新增一台虚拟机的I/O p95需求:20 IOPS。
对应结果约为:
- CPU:4.1 ÷ 0.018 ≈ 227台;
- 内存:16.8GiB约等于17,203MiB,17,203 ÷ 90 ≈ 191台;
- I/O:3,500 ÷ 20 = 175台。
因此,在这组示例条件下,I/O是限制因素,不能因为CPU还能增加约227台,就继续增加虚拟机。实际生产还应扣除增长余量,并考虑不同虚拟机峰值是否同时出现。若新增加的是I/O型虚拟机,I/O限制会更早到达;若新增加的是内存型虚拟机,限制项可能转为内存。
结果如何判定,什么时候必须复测
一轮测试通过的基本条件
不建议用单一阈值判断“200台成功”。更合理的通过条件是多个条件同时满足:
- 200台稳定负载下,吞吐量仍随并发增加而增长,没有明显平台期;
- 应用p95、p99响应时间满足业务自身目标;
- 错误率和超时率没有随着并发阶段持续上升;
- 宿主机CPU p95低于设定的目标线,运行队列没有持续增长;
- 虚拟机steal没有在高负载阶段持续扩大;
- 内存PSI、swap和major fault没有形成持续趋势;
- 存储p99延迟和队列在稳定负载下可控;
- 突发结束后,CPU、I/O队列和响应时间能够在约定时间内恢复;
- 单台高负载虚拟机不会让其他虚拟机的p99响应时间明显恶化。
业务目标不同,阈值也不同。交互式服务可能更关注p99延迟,批处理服务可能更关注吞吐量和完成时间,数据库类业务可能更关注I/O尾延迟。可以把“p95小于200ms、p99小于500ms、错误率小于0.5%、突发后5分钟内恢复”作为一组示例目标,但不能把它当成所有业务的通用标准。
出现不同结果时的处理方向
| 结果组合 | 优先检查方向 |
|---|---|
| CPU高、steal高、I/O正常 | vCPU超分、CPU调度、单台虚拟机抢占 |
| CPU中等、内存PSI高、swap高 | 实际工作集、内存超分、批量启动峰值 |
| CPU和内存正常、I/O队列高 | 随机I/O比例、单台虚拟机噪声、存储延迟 |
| 资源正常但网络重传高 | 网卡错误、队列、软中断、测试路径 |
| 平均值正常但p99恶化 | 短时突发、队列堆积、少数异常虚拟机 |
| 停止负载后迟迟不恢复 | 交换、缓存重建、I/O队列或后台任务积压 |
如果只调整了监控采样频率、虚拟机vCPU数量、内存气球、磁盘缓存、I/O限速或CPU调度参数,就应重新进行完整测试。只复测发生变化的单项,容易遗漏资源之间的联动影响。
以下情况也需要复测:
- 增加虚拟机数量或改变虚拟机类型比例;
- 单台虚拟机的vCPU或内存配置变化;
- 存储池、文件系统、缓存模式或磁盘队列配置变化;
- Linux内核、QEMU、libvirt或虚拟机镜像变化;
- 业务并发、数据集大小或读写比例变化;
- 200台虚拟机从低负载改为长时间持续负载;
- 业务开始出现批量启动、定时任务或集中备份类I/O。
下一次测试不要只记录“CPU利用率、内存使用率、磁盘利用率”三项平均数,而应至少同时观察这一组指标:宿主机CPU与运行队列、虚拟机steal、内存PSI与swap、存储p99 await与队列深度、应用吞吐与p99响应时间、网络重传与错误率。只有这些指标在同一时间窗口内保持稳定,200台KVM虚拟机的资源超分才具备可解释的性能边界和可执行的增长余量。