虚拟机性能优化20个核心技巧:从硬件到驱动的实战指南

发布时间:2026/10/20 6:46:33
虚拟机性能优化20个核心技巧:从硬件到驱动的实战指南
做虚拟化的朋友十个有八个都碰到过这种场景虚拟机刚装好跑起来就卡CPU 明明分配了不少但负载还是居高不下磁盘一压测就掉链子网络吞吐死活上不去。这类问题我前前后后排查了不少最后发现绝大多数性能瓶颈根本不是硬件不够而是踩在了一些常见的配置和驱动选择上。这次我把这几年攒下来的虚拟机性能优化经验整理成 20 个核心技巧每一个都是能直接落地、能验证的实操手段不是 PPT 上的理论。先说清楚一个基本思路虚拟机性能优化不是让你盲目给客户机加 CPU、加内存而是要把虚拟化这层中间商对硬件请求的额外损耗压到最低。文章会按照硬件底层、CPU 与内存、存储、网络、客户机内部、监控排查这几个维度去拆每一个维度都对应具体的操作方法和参数示例。只要你不是第一次接触虚拟化跟着走一遍应该就能看到明显变化。1. 先把思路理清虚拟机性能问题的本质1.1 瓶颈可能藏在这四个层级常有人一发现虚拟机慢就先把 CPU 核心数调大、内存翻倍结果还是慢。原因很简单虚拟机性能问题不是单点的而是沿着一条完整链路传递的。这条链路从下往上分四层。第一层是宿主机硬件包含物理 CPU 的拓扑结构、内存通道、磁盘控制器能力、网卡型号。第二层是虚拟化层包含虚拟机管理器采用的 CPU 虚拟化方式、内存页管理、磁盘控制器模拟、网络虚拟化方案。第三层是客户机系统本身包含操作系统的内核版本、驱动类型、文件系统选项、后台服务数量。第四层才是跑在虚拟机里的应用比如数据库、Java 应用、Web 服务。你可以把这四层想象成一条快递分拣流水线快递从卸货口进来经过传送带、扫描枪、分拣员最后才到对应打包区。任何一个环节慢了后面全部积压。很多时候问题出在第一层和第二层但表现出的症状却在第四层所以不动链路只在应用层反复调参自然不会有结果。这也是为什么我做优化时第一步永远是先确定瓶颈在哪一层而不是先改参数。有个很典型的情况某台虚拟机 CPU 显示 100%但物理机上查看 CPU 使用率并不高同时出现比较高的 steal 指标那问题基本就出在 vCPU 的调度和超配上而不是应用真的需要那么多计算能力。1.2 先谈收益排序什么优化最值得做根据我这些年实测的经验优化收益的排序和大多数人直觉不太一样。磁盘虚拟化驱动的收益几乎总是最高的能把模拟 IDE 换成半虚拟化 VirtIO 的情况下吞吐量提升经常是翻倍甚至更多的。其次是网络虚拟化换驱动和开多队列之后小包转发能力提升非常明显。然后是 CPU 与内存的亲和性调度这个对延迟敏感型应用尤其重要。再往后才是客户机内部的系统精简最后才轮到硬件直通这类比较重的方案。这里提醒一句做任何优化之前一定要做一次基线测试。没有基线你连改完之后到底有没有变好都不知道。我见过有同行在调整 vCPU 热插拔之后凭感觉觉得好像变快了结果 fio、iperf 的压测数据根本没变化纯粹是心理作用。后面第 6 部分我会专门讲怎么压测和采集数据。2. 硬件层优化别让虚拟化输在起跑线上2.1 CPU 超线程与 NUMA 拓扑感知虚拟化优化要从物理机层面先打好底子。第一个必查项是物理 CPU 的硬件辅助虚拟化开关。以常见 x86 平台为例BIOS 里对应 Intel 的叫 VT-x对应 AMD 的叫 SVM这两项如果没开虚拟机只能靠纯软件模拟指令性能损耗大得离谱。检查方法很简单Linux 宿主机上执行lscpu或者grep -E vmx|svm /proc/cpuinfo看到标志位就说明已经开启。这是个基础中的基础但真的遇到过新机房机器没开的情况。第二个容易踩坑的是超线程。很多人在宿主机上看到lscpu显示 32 个 CPU就觉得能分给虚拟机 32 个 vCPU。实际上如果是 16 核 32 线程那物理核心只有 16 个vCPU 一旦超过物理核数调度器只能把工作挤到同一个物理核上的两个逻辑线程去跑。对计算密集型负载来说超线程带来的提升通常只有 10% 到 20%不是翻倍。所以给虚拟机分配 vCPU 基础配额的时候最好按物理核心数来规划甚至对延迟敏感的业务要保证 vCPU 与物理核心一一绑定。第三件事是 NUMA 拓扑感知。拿常见的双路服务器来说内存访问本地节点和远端节点的延迟差距可能到 0.5 倍以上。如果你创建的虚拟机内存在物理机上被分配到了远端 NUMA 节点那内存时延会很难看。操作思路是通过numactl --hardware查看节点布局然后在虚拟机 XML 里配置numatune或者用 QEMU 的-numa参数让 vCPU 和内存落在同一节点。很多商业平台会自动处理但开源虚拟化组合需要手工做。2.2 内存带宽、预留与硬件辅助虚拟化CPU 之外的另一个硬件底子是内存。第一件事是确认内存带宽没有被其他虚拟机挤占。虽然内存超分是虚拟化的常规操作但对数据库、大数据这类吞吐型应用内存带宽是有限资源超分会导致 cache miss 时所有虚拟机都变慢。我的习惯是高优先级虚拟机配置内存预留确保物理内存页真实分配给这台虚拟机不会被换出到 swap 或者被内存气球回收。具体到实现KVM/QEMU 环境下通常可以在虚拟机 XML 里配置memoryBackinglocked//memoryBacking效果等同于把内存页锁在物理内存中防止被 swap。这个操作对虚拟机内部使用大页的场景尤其重要。另外提一下刚才说的 VT-x/AMD-V除了 CPU 指令虚拟化外还有一个容易被忽略的是 IOMMU也就是 Intel 的 VT-d 或 AMD 的 AMD-Vi。它负责的是设备直通能力比如把物理网卡、NVMe 盘直接给虚拟机用。如果 BIOS 里没开后面想用直通方案会直接失败。检查方法是dmesg | grep -i iommu或者看/sys/kernel/iommu_groups/是否有内容。3. CPU 与内存优化算力与缓存的精细调度3.1 vCPU 颗粒度确定性比堆核数更重要很多运维同行习惯把虚拟机的 vCPU 数量配置到宿主机上限他们觉得多点总比少点好。但 vCPU 并不是免费的调度器要为每个 vCPU 维护独立的运行队列虚拟机的每个 vCPU 都会参与宿主机 CPU 调度vCPU 数量过多反而会把时间片切得更碎造成 cache 命中率下降和上下文切换开销。正确做法是参考应用的实际负载曲线。比如某个应用压测时最多使用 8 个线程那给虚拟机配 8 个 vCPU 基本够用。这里补充一个经验对于数据库类应用vCPU 数量最好略大于运行线程数因为数据库的并行查询、后台写线程、日志线程会同时抢 CPU。对于 CPU 密集型小应用4 个 vCPU 以内通常足够。在追求确定性的时候推荐配置 vCPU pinning也就是把虚拟机的每个 vCPU 固定到宿主机指定的物理 CPU 上。用 virsh 操作很简单virsh vcpupin my-vm 0 8 virsh vcpupin my-vm 1 9 virsh vcpupin my-vm 2 10 virsh vcpupin my-vm 3 11上面的意思是虚拟机的 vCPU 0 到 3 分别绑到物理 CPU 8 到 11 上。这样做的好处是避免了 vCPU 在不同物理核之间迁移从而减少 TLB 和 cache 失效。代价是该物理核不能被其他虚拟机占用相当于做了一部分资源隔离。这里还有一个细节即使配置了 pinning也要保证同一物理 NUMA 节点内分配不然 vCPU 访问远端内存反而比不 pin 更慢。这又回到了 NUMA 拓扑感知那一节所以这两项最好一起做。3.2 大页、气球与内核参数的三重奏内存部分最容易出效果的是大页。默认情况下 Linux 用 4KB 大小的内存页虚拟机的内存访问会产生大量 TLB 查找CPU 的 TLB 容量是有限的一旦 cache miss 就要走页表遍历。把内存页改成 2MB 甚至 1GB 之后同样的 TLB 能覆盖的内存空间变大大量业务的访存时延会明显下降。在 KVM 环境里宿主机可以预先分配大页# 分配 2MB 大页池共 1024 个也就是 2GB echo 1024 /proc/sys/vm/nr_hugepages然后在虚拟机 XML 里配置memoryBackinghugepages//memoryBacking或者用 QEMU 参数-mem-path /dev/hugepages。生产环境中如果有条件可以用 1GB 大页对数据库类应用效果更明显但 1GB 页池需要内核启动参数default_hugepagesz1G hugepagesz1G hugepagesN来配置属于重启宿主机级别的大动作建议先在测试环境验证。比大页更需要警惕的是透明大页 THP。宿主机开启 THP 时内核会在后台自动把普通页合并成大页听着很美好但合并过程会触发内存规整规整时可能出现明显的延迟尖峰。在虚拟化宿主机上这个尖峰可能传导给所有虚拟机数据库应用尤其敏感。我的建议是宿主机直接关闭 THP客户机内如果跑的是数据库也关闭 THP。echo never /sys/kernel/mm/transparent_hugepage/enabled echo never /sys/kernel/mm/transparent_hugepage/defrag内存气球的逻辑也值得一提。通俗地说内存气球可以动态把空闲内存从虚拟机借回宿主机听起来很灵活但如果应用内存不规律增长气球回收内存时可能引发客户机 swapping。在高优先级虚拟机中要么禁用气球要么把最小内存设置为预留值避免运行时收缩。4. 存储 I/O 优化绕过慢速层的关键手段4.1 选对控制器与总线VirtIO、直通与 SR-IOV存储部分是我最强调的一块。很多新手建虚拟机时直接选 IDE 或 SATA 控制器这其实是在用一套模拟老硬件的方案跑现代磁盘CPU 要在指令层模拟磁盘控制器的寄存器、中断和 DMA 行为开销非常大。换用 VirtIO 半虚拟化方案后虚拟机和宿主机通过共享内存队列直接传 I/O 请求省掉了一整层模拟过程。在 QEMU 命令行里一个好的 VirtIO 块设备配置大致长这样-drive file/data/vms/disk.img,ifnone,formatqcow2,aionative,cachenone \ -device virtio-blk-pci,drivedisk1,scsioff这里的aionative是让 QEMU 使用 Linux 原生异步 I/O 接口而不是用户态模拟cachenone是绕过页缓存直接读写两者对吞吐和延迟都有正面影响。进入客户机后确认系统里加载了 virtio_blk 驱动磁盘名称一般是/dev/vda而不是/dev/sda。如果业务对延迟极其敏感或者需要跑大规模随机读写可以考虑 NVMe 盘直通。直通的本质是把物理设备直接划给某台虚拟机中间不再经过宿主机虚拟化协议栈效果接近于裸机性能。直通的配置需要在虚拟机 XML 里添加hostdev设备并且依赖前面说的 IOMMU 开启。另外一个折中方案是 SR-IOV它可以让一块物理设备虚拟出多个功能每一个功能都能作为独立设备分配给虚拟机既保留了直通的大部分性能又支持一卡多机。NVMe SR-IOV 和网卡 SR-IOV 我都试过后者在生产中更成熟。4.2 后端搅动IOThread、缓存策略与队列深度即便用了 VirtIO如果宿主机侧 I/O 提交路径不合理瓶颈依然会很明显。QEMU 默认把 I/O 处理丢进主循环所有虚拟机的块设备请求可能挤在同一个线程里排队。更合理的方式是为每台虚拟机单独创建 IOThread。-object iothread,idio1 \ -device virtio-blk-pci,drivedisk1,iothreadio1IOThread 的好处是让块设备中断和请求处理拥有独立的 CPU 上下文避免和其他虚拟机的 I/O 互相干扰。配合 CPU pinning把 IOThread 绑在特定物理核上效果更好。这个操作对于高 IO 的虚拟机提升非常直观我自己压测过的场景里随机读 IOPS 能提升 15% 到 30%。缓存策略这块我特别想多说两句。很多人想当然选 writeback觉得写性能最高但 writeback 意味着数据先写到宿主机的页缓存里如果此时宿主机掉电数据并没有真正落盘风险很大。生产环境更推荐cachenone配合有电池保护的 RAID 卡或企业级 SSD让写操作直接透传到底层存储。只有跑临时测试、缓存类应用时才考虑 writeback。还有一个容易被忽略的参数是队列深度。VirtIO 块设备默认队列数量有限通过num-queuesN参数可以增加多队列支持让 I/O 并发度更高。客户机里的磁盘调度器也值得调整SSD 场景建议用none机械盘场景建议用deadline因为默认的cfq在高并发下经常成为瓶颈。修改调度器很简单echo none /sys/block/vda/queue/scheduler5. 网络虚拟化优化打满数据通路5.1 虚拟网卡与多队列先解决最基础的损耗网络虚拟化的问题和存储虚拟化类似最重要的还是驱动模型。默认建虚拟机时如果选的是 e1000 这类模拟网卡CPU 需要模拟完整的中断和 DMA 流程数据包一多就明显跑不动。换 VirtIO 网卡之后客户机和宿主机之间通过共享内存环形队列交换包开销小了一个数量级。除了驱动类型多队列的设置也关键。默认 VirtIO 网卡只有一个队列意味着所有包都交给宿主机侧一个处理线程多核 CPU 根本用不满。打开多队列后每个队列可以绑定到不同的 CPU包处理能力才能水平扩展。QEMU 侧的配置大致如下-netdev tap,idnet1,queues4 \ -device virtio-net-pci,netdevnet1,mqon,vectors10进入客户机后还需要设置队列数量。可以在客户机内用 ethtool 确认和调整ethtool -L eth0 combined 4多队列的收益在小包高并发场景特别明显。举个我压测过的例子默认单队列时64 字节小包转发率只有 20 万 PPS 左右开 4 队列后能到 60 万 PPS几乎是线性扩展。5.2 中断、卸载特性与网卡直通队列开好了还要让队列的中断平均分布到不同 CPU 上否则所有中断挤在 CPU0 上其他核虽然在跑但还是有一个核被打满整体吞吐上不去。VirtIO 网卡支持接收侧缩放也就是 RSS打开后驱动会按照哈希自动把连接分散到多个队列。客户机内确认 RSS 是否生效ethtool -l eth0 ethtool -n eth0 rxfh indir另外一定要检查网络卸载特性。现代网卡支持校验和卸载、TSO/GRO、GSO 等特性让 CPU 不用处理每一个包头的校验和计算而是交给网卡硬件完成。VirtIO 半虚拟化环境下也可以透传这些卸载能力客户机内检查ethtool -k eth0看到tx-checksumming: on、scatter-gather: on、tcp-segmentation-offload: on、generic-receive-offload: on这些字段都是 on 就说明没问题。如果发现它们被关了可以用ethtool -K eth0 tso on gso on gro on开启。如果网络延迟要求极高比如金融交易类应用多队列仍然不够可以考虑网卡直通。直通网卡相当于虚拟机独占物理网卡数据包不经过宿主机协议栈延迟可以压到接近裸机。代价是灵活性下降热迁移基本没法用主机故障时这台虚拟机也没办法自动漂移到其他宿主机所以只有明确的高性能需求才建议使用。6. 客户机内与监控排查最后一公里的隐藏收益6.1 客户机系统精简与服务裁剪操作系统层面的优化经常被高估但剩下的那一部分确确实实能吃到嘴里。最直接的是在装系统时选择最小安装不装图形界面。图形桌面会占用大量内存还会周期性执行后台任务对服务器虚拟机来说纯属浪费。我见过一台 8GB 内存的虚拟机只因为装了桌面和一堆默认服务空闲内存就少掉 1.5GB 以上。装完系统后还要清理非必需服务。常见的 cron、邮件服务、打印服务、桌面相关的 dbus 会话、不必要的审计服务都在清单里。虚拟机跑的如果不是容器化应用建议把 swap 调低避免应用在内存充足时也去 swap。另一个经常被忽略的点是系统内核版本较新内核对于 VirtIO 驱动的性能和稳定性都有改进所以不要长期停在老版本内核上。客户机内的 CPU 频率调节器也值得看一眼。默认的powersave或ondemand调节策略在突发负载下会有明显的频率爬升延迟而performance策略则让 CPU 始终保持在最高频率。对于延迟敏感业务建议直接固定 performancecpupower frequency-set -g performance6.2 用数据说话监控指标与典型瓶颈识别最后是监控和排查环节。如果没有数据支撑前面所有优化都像是在猜。我常用的工具组合是top、vmstat、iostat、pidstat、perf压测工具是fio和iperf3。重点看这几个指标CPU steal是虚拟机里非常有参考价值的指标用 top 看客户机 CPU 时如果 steal 百分比高说明宿主机 CPU 资源紧张vCPU 在等待调度这时候优化应用没用应该去调整宿主机超分和 pinning。客户机内vmstat的r列代表运行队列持续大于 vCPU 数量说明计算资源不足si/so如果持续有值说明内存不够或 swap 频繁应优先检查宿主机内存预留和气球的设置。磁盘方面用iostat -x 1看%util和await。%util接近 100% 并不一定代表磁盘满负荷有可能只是队列深度太浅这时候需要增加 virtio 队列或调整调度器。await明显升高则可能说明底层存储延迟变大要看宿主机那边是否有其他虚拟机在抢 IO。分享一个真实案例某台虚拟机数据库查询从原来的 10 毫秒变成 200 毫秒客户机内iostat显示await高但%util并不高。开始以为是磁盘坏了后来在宿主机上观察才发现另一台备份虚拟机的fio压测正在跑磁盘队列被占满导致延迟飙升。最后通过给高优先级虚拟机配置 IOThread 和 pinning问题才缓解。这类问题除了工具更重要的是有一个宿主机全局视角要习惯在宿主机上做排查而不是只在虚拟机里面打转。7. 20 个核心技巧速查与经验底线7.1 速查表20 个核心技巧一览把上面聊到的内容整理成一张速查表方便随时对照。编号优化维度关键操作收益与场景1硬件层开启 CPU 硬件辅助虚拟化VT-x/SVM基础必查项虚拟化能用的前提2硬件层识别超线程按物理核规划 vCPU 基础配额避免 vCPU 超卖引发计算抖动3硬件层NUMA 拓扑感知vCPU 与内存同节点减少跨节点内存访问延迟4内存配置大页或 1G 大页降低 TLB miss适合数据库类5内存关闭透明大页 THP避免内存规整带来的延迟尖峰6CPU按负载曲线配置 vCPU不盲目堆核减少调度和 cache 开销7CPUvCPU pinning 绑定物理核心提高延迟敏感业务的确定性8内存内存锁定禁止 swap防止高优先级虚拟机内存被换出9内存设置合理的气球最小内存避免气球回收引发客户机 swapping10存储使用 VirtIO 块设备替代 IDE/SATA吞吐提升最明显的基础操作11存储NVMe 直通或 SR-IOV极低延迟、极高 IOPS 场景12存储配置 IOThread 并绑定 CPU隔离 I/O 处理IOPS 提升明显13存储缓存策略选 none数据安全优先防止掉电丢数据14存储调整队列深度和调度器适配 SSD/HDD提升并发度15存储均衡 SSD/HDD 混布场景带宽防止低优先级 IO 拖垮高优先级业务16网络VirtIO 网卡替代模拟型号改善吞吐和 CPU 开销17网络开启多队列并设置队列数量小包高并发场景线性扩展18网络配置中断合并与 CPU 亲和避免单核中断热点19客户机最小化安装系统并精简服务减少无谓资源占用20方法论建立基线测试一次只改一个变量让优化结果可量化、可回滚7.2 我的几条铁律和一些补充表里第 20 条看起来不像技巧但我觉得它其实最值钱。虚拟机性能优化的难点从来都不是有哪些参数能调而是在正确的时间动正确的参数。刚开始接触这些优化手段的时候我也喜欢一次开一堆开关结果性能变好或者变坏都不知道是谁的功劳出了问题回滚都不知道该回滚哪儿。后来养成了一个习惯每次优化前先记录当前配置和压测数据然后只改一个变量再压一次记录在案。按照这个流程走下来优化是在稳步推进的而不是靠运气。另外补充两个容易踩的坑。第一生产环境做优化之前一定要看虚拟化平台是否支持热调整。有些参数比如 CPU pinning需要重启虚拟机才生效如果这台机器正在跑关键业务要考虑变更窗口。第二不要为了跑分过度追求直通。直通确实性能好但会牺牲虚拟化的灵活性和高可用能力一台生产虚拟机的价值往往不在单机性能而在整个集群的稳定调度能力。一台虚拟机一旦依赖物理设备故障恢复的复杂度会成倍增加。就说这么多希望对正在弄虚拟机性能优化的朋友有点帮助。如果你手头也有类似的场景先别急着堆配置按我上面说的链路顺序从宿主机硬件到虚拟化层再到客户机一层层查配合基线数据去改你会发现自己也能快速定位到真正的瓶颈。这些方法不需要多高深的理论就是一遍一遍实践出来的教训用好了就是一套很顺手的工具。