跳转到内容

磁盘 IO 调优:IO thread、缓存模式与 aio ​

创建第一个虚拟机里已经给过磁盘选项的入门建议:IO thread 勾上、Cache 保持默认。这篇把这几个选项拆开讲清楚它们各自做什么、什么时候值得改,以及缓存模式里最容易踩的坑。

先确认瓶颈真的在磁盘 IO

sh
# 宿主机 shell
iostat -x 2 5

看 %util 是否接近 100%、await 是否明显偏高。如果磁盘本身不忙,问题通常在别处:客户机没装 VirtIO 驱动(还在用模拟 IDE/SATA)、存储池写满导致性能骤降、多个备份任务同时在跑。这些排除之后,才轮到这篇的参数。

收益排序:先做这几件事 ​

  1. 磁盘总线用 SCSI,控制器选 VirtIO SCSI single。 这是模拟设备和半虚拟化设备的差距,数量级的影响,比下面任何一个参数都重要。
  2. 客户机确认装了 VirtIO 驱动(Linux 内置,Windows 需要装 virtio-win 驱动包)。
  3. 存储池别写太满。 ZFS 超过约 80% 使用率后写入性能明显下降,LVM-Thin 写满会直接导致客户机写入失败。
  4. 做完以上三条,再看 IO thread、cache、aio 这些细项——它们的收益比前三条小得多。

IO thread:把磁盘 IO 挪出主线程 ​

默认情况下,虚拟机的磁盘 IO 由 QEMU 的主线程或 vCPU 线程处理,和 CPU 计算抢时间片。勾选 IO thread 后,QEMU 为这块磁盘单独开一个线程处理 IO,主线程和 vCPU 不再被磁盘操作阻塞。

适用条件代价
磁盘总线是 SCSI 且控制器是 VirtIO SCSI single,或者总线是 VirtIO Block几乎没有代价,官方从 PVE 7.3 起对新建 Linux 虚拟机默认勾选

为什么必须搭配 VirtIO SCSI single

用共享控制器(VirtIO SCSI,不带 single)时,一个控制器上挂的所有磁盘共用一个 IO 线程,IO thread 的隔离效果打折扣。VirtIO SCSI single 给每块盘一个独立控制器,IO thread 才能真正做到磁盘之间互不阻塞。

aio:宿主机怎么发起磁盘 IO 请求 ​

aio 决定 QEMU 向宿主机内核提交 IO 请求用哪种机制,在磁盘的高级选项里设置。

值说明适用条件
io_uring较新的 Linux 异步 IO 接口,开销更低PVE 9 默认使用,内核较新(PVE 8/9 的默认内核都支持)
nativeLinux AIO(较老的异步 IO 接口)部分存储后端或旧内核的兼容选项
threads用线程池模拟异步 IO兼容性最好,某些存储类型(如挂载的网络文件系统)只能用这个

大多数情况下保持 PVE 给出的默认值即可。只有在排查具体的 IO 延迟或吞吐问题、并且已经通过基准测试对比过时,才考虑手动切换,而且要在测试环境先验证客户机能正常启动——不是所有存储后端都支持每一种 aio 模式。

缓存模式:这是唯一需要认真读警示块的一项 ​

cache 决定虚拟机的写入什么时候被认为"完成",以及宿主机页缓存参与到什么程度。

模式宿主机页缓存写入语义掉电风险
No cache(默认)不使用宿主机缓存,直连存储客户机收到"写完成"时,数据已经交给了后端存储的写入路径低,是官方推荐的默认平衡点
Writethrough使用宿主机读缓存每次写入都等待落盘确认才返回低,但性能通常不如 No cache
Writeback使用宿主机读写缓存客户机收到"写完成"时,数据可能还停留在宿主机内存里没有落盘高
Directsync不使用宿主机缓存类似 Writethrough,但绕过宿主机页缓存直接同步低,性能通常最差
Unsafe使用宿主机读写缓存,且忽略客户机的同步请求客户机主动要求"把这批数据刷盘"时,宿主机可能直接忽略极高

writeback 和 unsafe 用性能换掉电时的数据完整性

Writeback 和 Unsafe 更快的原理是:告诉客户机"写完成了",但数据实际还在宿主机内存的缓存里,稍后才真正落盘。如果这时候宿主机异常断电、内核崩溃或被强制关机(而不是正常关机),这部分还没落盘的数据会丢失——对客户机来说,这表现为文件系统损坏、数据库文件不一致,轻则某些最近的写入消失,重则整个文件系统需要修复甚至无法挂载。

Unsafe 更进一步:它会忽略客户机文件系统主动发出的刷盘请求(fsync/flush),这些请求本来是数据库、日志类应用用来确保关键数据落盘的最后手段,在 Unsafe 模式下也不可靠。它的合理使用场景几乎只有:一次性的、坏了可以重新生成的场景(例如从头批量转换镜像格式的临时虚拟机),不要在保存真实数据的虚拟机上使用。

影响范围:整块虚拟机磁盘上未落盘的写入,无法预知具体丢失哪些数据。 前置条件:已经有对应的 UPS 并验证过自动关机脚本有效,或者能接受这块盘上数据在异常断电时損坏。 回退方式:把 Cache 改回 No cache,虚拟机需要重启一次生效;如果已经发生过异常断电,回退之前应先检查客户机文件系统(fsck 或对应文件系统的检查工具)。

改缓存模式:虚拟机 → Hardware → 硬盘 → Edit → Cache,或者宿主机 shell:

sh
# <vmid> 是虚拟机编号,<diskbus><n> 例如 scsi0
qm set <vmid> --scsi0 <storage>:vm-<vmid>-disk-0,cache=writeback

discard 和 SSD 仿真不属于缓存问题

Discard(把客户机删除文件后的 TRIM 请求传给底层存储,依赖精简置备存储和支持 TRIM 的客户机)和 SSD emulation(让客户机认为自己在 SSD 上)都不影响掉电时的数据完整性,和 cache 模式是两回事,可以按需单独开启。

检查结果 ​

sh
# 宿主机:确认配置已生效
qm config <vmid> | grep -E 'scsi|virtio|ide'

输出里能看到 cache=、aio=、iothread=1 等字段(未显示 cache= 表示使用默认的 No cache)。

用基准测试(见基准测试方法)在改动前后各跑一次,对比延迟和吞吐——没有对比数据,不知道改动到底有没有用。

常见问题 ​

改了 cache 之后没生效。 磁盘的 cache/aio/iothread 是 QEMU 进程启动时决定的,需要关机再开机(Shutdown 后 Start),重启操作系统(Reboot)不够。

用了 Writeback,现在担心已有虚拟机的数据完整性。 先确认这段时间宿主机没有发生过异常断电或崩溃。如果发生过,进入客户机检查文件系统状态,必要时从备份恢复而不是相信"看起来还能用"。

某些存储类型改 aio 后虚拟机起不来。 换回默认值,不是所有 aio 模式都被所有存储后端支持,尤其是网络文件系统类存储。

参考资料 ​

Proxmox VE 非官方中文使用指南,与 Proxmox Server Solutions GmbH 无隶属关系。