从库磁盘IO高应优先调优三项:设innodb_flush_log_at_trx_commit=2、sync_binlog=0(未开log_slave_updates时)或10、sync_relay_log=10000;同时挂载参数加noatime,nobarrier,commit=60。

从库磁盘IO高,先看 innodb_flush_log_at_trx_commit 是不是设成了 1
MySQL 默认把 innodb_flush_log_at_trx_commit 设为 1,每次事务提交都强制刷盘一次 ib_logfile,对从库这种高并发回放场景就是 IO 灾难——尤其当主库写入压力大、从库还没追上时,日志堆积 + 频繁刷盘会直接打满磁盘带宽。
实操建议:
- 从库可以安全设为
innodb_flush_log_at_trx_commit = 2:日志只写入 OS 缓存,每秒刷一次盘,崩溃最多丢 1 秒数据,但对复制一致性无影响(因为从库不对外提供写服务) - 绝对不要设成 0:虽然 IO 更低,但 MySQL 进程崩溃会导致未刷盘日志丢失,可能让从库回放中断甚至数据不一致
- 修改后必须重启 MySQL 或执行
SET GLOBAL innodb_flush_log_at_trx_commit = 2(注意该变量动态生效需innodb_log_file_size足够大,否则可能触发重做日志切换抖动)
检查 sync_binlog 是否在从库也开了 1
主库开 sync_binlog = 1 是为了保证主库 binlog 不丢,但从库根本不用写 binlog(除非开启了 log_slave_updates),如果误开了,等于凭空多一层强制刷盘,白耗 IO。
实操建议:
- 确认从库是否启用了
log_slave_updates:没开就直接把sync_binlog设为 0;开了则按需设为 1 或 10(比如要求强一致性才设 1) - 用
SHOW VARIABLES LIKE 'sync_binlog'和SHOW VARIABLES LIKE 'log_slave_updates'快速验证 - 注意:MySQL 8.0.28+ 支持
sync_binlog = OFF字符串写法,但旧版本只认数值,设成OFF会静默转成 1,反而更糟
从库 IO 高还可能是 relay log 刷盘太勤,盯紧 relay_log_space_limit 和 sync_relay_log
relay log 是从库中转日志,如果 sync_relay_log = 1(默认值),每个事务写完 relay log 就刷盘,和主库的 sync_binlog = 1 效果一样——纯 IO 浪费。再叠加 relay_log_space_limit 过小,频繁轮转 relay log 文件也会触发额外 IO。
实操建议:
- 从库设
sync_relay_log = 10000(或 0,但 0 表示仅在事务提交时刷,不如 10000 稳定):降低刷盘频率,实测可降 IO 30%~50% -
relay_log_space_limit至少设为 2G 以上(比如2147483648),避免因空间不足频繁新建/删除文件 - 观察
SHOW SLAVE STATUS\G中的Relay_Log_Space值,如果长期接近relay_log_space_limit,说明限制太紧,得调大
别忘了系统层:ext4 的 data=ordered 和挂载参数也在拖后腿
MySQL 数据目录挂在 ext4 上时,若用默认挂载选项(如 data=ordered),每次写入都会触发元数据更新和 journal 刷盘,和 InnoDB 自身刷盘叠加,IO 放大效应明显。特别是从库 replay 速度慢、relay log 和 ibdata 写入交织时,更容易卡住。
实操建议:
- 确认挂载参数:
mount | grep mysql,重点看有没有data=journal(禁用!)或缺失noatime,nobarrier - 推荐挂载选项:
defaults,noatime,nobarrier,commit=60(commit=60把 ext4 自身日志提交周期拉长到 60 秒,大幅减少 journal 刷盘次数) - 改完需重新 mount,不能只改
/etc/fstab就以为生效;且务必先停 MySQL,否则可能损坏文件系统
真正麻烦的不是参数本身,而是这些设置之间会互相放大副作用——比如 innodb_flush_log_at_trx_commit = 1 搭配 data=ordered,IO 峰值可能翻倍。调一个之前,先用 iostat -x 1 看清到底是谁在写、写多大、等待多久。


















