Windows Server上MySQL 8.0 IOPS瓶颈主因是Windows文件系统缓存与InnoDB双重缓冲、IO线程数不足(默认4)、NTFS 4KB簇与InnoDB 16KB页不匹配;必须设innodb_flush_method=unbuffered、innodb_read/write_io_threads=12、格式化磁盘为64K分配单元,并禁用卷影复制等干扰服务。

直接改 innodb_io_capacity 数值没用,NVMe 的真实瓶颈在 Windows 文件系统缓存、InnoDB 线程调度和 NTFS 分配单元错配——这三处不调,再快的盘也跑不满 IOPS。
Windows Server 上必须设 innodb_flush_method=unbuffered
Linux 下的 O_DIRECT 在 Windows 完全不生效;留空或设 normal 会触发双重缓冲(NTFS 缓存 + InnoDB buffer pool),大量小写被复制两次。实测中 pending normal aio reads 持续积压,正是这个原因。
-
unbuffered是 Windows 唯一真正绕过系统缓存的选项;async_unbuffered已弃用且在高并发下易触发崩溃 - 必须配合
innodb_use_native_aio=1(默认开启),否则 AIO 请求退化为同步阻塞 - 若启动报错
io_setup() failed with EAGAIN,不是参数错,而是系统未启用 I/O 完成端口(IOCP)权限,需以管理员身份运行 mysqld
innodb_read_io_threads 和 innodb_write_io_threads 至少设为 12
Windows 默认是 4,而现代 NVMe SSD 能轻松支撑 20+ 并发队列深度。线程数不足时,SHOW ENGINE INNODB STATUS 中的 pending aio 会长时间非零,任务管理器看到磁盘队列长度 > 10 但实际吞吐上不去。
- 建议设为逻辑 CPU 核心数 × 0.75(如 24 核服务器设 18);超过 24 反而因线程争抢 IOCP 句柄导致延迟上升
- 不要盲目对齐 Linux 的
innodb_read_io_threads=4风格,Windows 的 IOCP 模型依赖足够线程来驱动完成端口轮询 - 该参数动态生效:
SET GLOBAL innodb_read_io_threads = 16,但重启后失效,必须写进my.ini的[mysqld]段
NTFS 格式化必须用 64K 分配单元
InnoDB 默认页大小是 16KB,而 NTFS 默认簇大小是 4KB。一次 16KB 写入会被拆成 4 次 4KB 物理写,产生严重写放大——尤其在 INSERT ... ON DUPLICATE KEY UPDATE 场景下,IOPS 利用率常卡在 30% 以下。
- 格式化命令必须为:
format /FS:NTFS /A:64K D:(D: 为数据盘) - 不能靠“分配单元大小”图形界面选,GUI 里最大只显示 4K,必须命令行强制指定
- 已格式化过的盘无法在线调整,重做前需备份
datadir并清空目录
最容易被跳过的其实是卷影复制(VSS):它会在后台持续扫描 MySQL 数据文件,与 InnoDB 的异步刷盘竞争磁盘带宽,哪怕你关了自动备份,VSS 服务仍在运行。禁用命令是 vssadmin delete shadows /all /quiet + 停止并禁用 Volume Shadow Copy 服务——这点比调参更影响实测 IOPS 波动。


















