linux下应设为o_direct,windows下用unbuffered;设错或不设会导致double buffering,浪费内存和io带宽。因mysql默认fsync()会先写入os page cache,叠加innodb buffer pool形成双重缓存,降低命中率、增加io碎片;o_direct绕过os缓存直写磁盘,避免冗余拷贝,尤其高并发或大buffer pool时效果显著。

Linux 下应设为 O_DIRECT,Windows 下用 unbuffered;设错或不设会导致 double buffering,白白吃掉内存和IO带宽。
为什么 innodb_flush_method 会影响性能
MySQL 默认用系统调用 fsync() 刷盘,但 Linux 上它会先写进 OS page cache,再由内核异步刷到磁盘——InnoDB 自己的 buffer pool + OS 缓存 = double buffering。这不仅浪费内存,还会让 innodb_buffer_pool_size 实际命中率下降,IO 请求也更碎更不可控。
设成 O_DIRECT 后,InnoDB 绕过 OS 缓存,直接把页写到磁盘设备,避免冗余拷贝,尤其在高并发写入或 buffer pool 较大时效果明显。
- 错误现象:iostat 显示
%util高但r/s、w/s不高,await波动大;free -h中 cached 占用持续偏高 - 不是所有存储都支持
O_DIRECT:某些 NFS、CephFS 或旧内核(如 CentOS 6)可能报Invalid argument启动失败 - 设了
O_DIRECT后,innodb_buffer_pool_size就真成了“唯一缓存层”,务必留够系统内存(至少 2–4GB),否则容易触发 OOM killer
怎么确认当前值和是否生效
连上 MySQL 执行:
SHOW VARIABLES LIKE 'innodb_flush_method';返回值必须是
O_DIRECT(Linux)或 unbuffered(Windows),不能是空或 fsync。
注意:innodb_flush_method 是只读变量,无法运行时修改,必须改配置文件后重启 mysqld。
- 检查 my.cnf 是否写在 [mysqld] 段下,格式为:
innodb_flush_method = O_DIRECT(无引号、无空格) - 启动时若报错:
InnoDB: Error: unable to open file ./ibdata1 with O_DIRECT,说明底层文件系统不支持,退回fsync并排查挂载选项(如 ext4 要禁用barrier=0或使用 XFS) - 生效后观察
cached值应明显低于未设时,且iostat -x 1中avgrq-sz更接近 16KB(InnoDB page size),而非随机小值
O_DIRECT 和 O_DSYNC 怎么选
O_DIRECT 是 Linux 下首选,它跳过 page cache,但依然用 fsync() 保证日志落盘;O_DSYNC 只对日志文件启用同步写,数据文件仍走缓存——这反而破坏一致性,且 MySQL 官方文档已明确标注该值“deprecated”。
- 别用
O_DSYNC:5.7+ 版本中它不会被识别,mysqld 会静默回退到默认fsync,且 error log 里不报错,极易误判 - SSD 场景下
O_DIRECT效果更稳;如果是 HDD + 大量随机写,可配合innodb_io_capacity(设为磁盘 IOPS)一起调 - 如果用了 LVM 或 dm-crypt,确认设备支持 direct IO:执行
dd if=/dev/zero of=/var/lib/mysql/test.direct bs=1M count=100 oflag=direct,不报错才算通过
真正起效的从来不是单个参数,而是 O_DIRECT + 合理的 innodb_buffer_pool_size + 匹配写负载的 innodb_log_file_size 三者咬合;漏掉任意一环,O_DIRECT 就只是把瓶颈从缓存搬到了磁盘队列上。











