MySQL主从架构中,从库承担重放中继日志的任务,当业务写入量上涨时,不少实例出现磁盘IO使用率长期高于百分之九十,导致SQL线程应用事件变慢、主从延迟不断增大。这种现象通常不是磁盘本身性能不足,而是日志刷新策略与系统IO相关参数没有针对从库角色做调优。从库不需要像主库那样在每次事务提交时都严格保证落盘,因为它本身不对外提供写服务,数据来源是主库已经提交过的二进制日志,因此可以在保证可恢复的前提下放宽部分持久化约束。

理解从库高IO的根因与日志刷盘机制
从库在回放事务时,同样会写InnoDB的redo日志和自身的binlog(若开启log_slave_updates),同时还会更新relay log信息。默认配置下,innodb_flush_log_at_trx_commit设为1表示每次事务提交都把redo刷到磁盘,sync_binlog设为1表示每次写入binlog都同步落盘。对于主库这是防止宕机丢数据的黄金组合,但从库每执行一个事务就触发两次强制刷盘,在大量小事务同步时会产生海量随机写,磁盘IO自然居高不下。
另一个被忽视的点是操作系统页缓存的回写行为。Linux默认脏页比例较高,从库大量写操作先驻留内存,后台flush线程集中刷出时会造成周期性的IO尖峰。如果此时再加上MySQL自身激进的日志策略,就会出现持续饱和。我们可以通过观察iostat -x 1中的await和util指标,以及MySQL状态变量Innodb_log_writes来确认是否日志写成为瓶颈,而不是查询读造成的压力。
中继日志的清理策略也会影响IO。若relay_log_purge开启,从库在重放完后异步删除relay文件,删除操作虽不频繁但会带来元数据写入。更重要的是,当从库开启了log_slave_updates且作为级联节点时,binlog写入量与主库等同,此时优化binlog刷新策略收益最大。理清这些写路径,才能有的放矢地调整参数而非盲目更换硬件。
调整MySQL日志刷新与事务提交参数
最核心的参数是innodb_flush_log_at_trx_commit和sync_binlog。对纯从库(不承接前端写、非级联主节点),可将其分别设为2和0或100。设为2时,redo日志每次提交写文件但不强制刷盘,依赖操作系统每秒刷一次;sync_binlog=0则由文件系统控制binlog刷盘时机。这样从库每秒最多一次强制刷盘,写次数下降一个数量级。下面给出典型配置片段:
-- 在从库配置文件 my.cnf 的 [mysqld] 段添加 innodb_flush_log_at_trx_commit = 2 sync_binlog = 0 relay_log_recovery = 1 log_slave_updates = 0
需要注意,若从库同时作为备份源或级联复制主库,log_slave_updates必须开启,此时sync_binlog不建议为0,可设为100平衡安全与IO。此外,增大innodb_log_buffer_size到16MB或32MB,能让更多日志在内存合并后再写,减少刷盘次数。配合innodb_log_file_size调大到1GB左右,降低日志文件切换频率,也能削减IO抖动。
除了全局参数,还可以控制从库并行回放worker数。设置slave_parallel_workers为8到16,并采用LOGICAL_CLOCK模式,让多个事务按提交顺序并行应用,缩短回放总时长,从而减少单位时间内的日志写压力。但并行度不是越高越好,过多线程会加剧锁竞争和上下文切换,反而让IO更零散。建议结合Performance Schema中的replication_applier_status表观察是否有等待。
协同优化操作系统IO调度与脏页控制
MySQL参数之外,系统层面对磁盘IO的影响同样关键。对于SSD,应将IO调度器设为none或mq-deadline,避免老旧的cfq带来额外排队开销。通过echo mq-deadline > /sys/block/sda/queue/scheduler即可临时调整。同时,修改/etc/sysctl.conf中的脏页参数,让系统更平滑地回写而非累积到阈值后暴刷:
# 控制脏页比例与回写时机 vm.dirty_background_ratio = 5 vm.dirty_ratio = 10 vm.dirty_expire_centisecs = 500 vm.dirty_writeback_centisecs = 100
上述配置把后台回写阈值降到百分之五,强制回写上限百分之十,并且每秒检查、五秒过期脏页,使得从库写内存后很快被分批刷出,避免突发大块写撑满IO队列。如果是机械盘,还可借助ionice提升MySQL后台线程优先级,或把redo、binlog、数据文件分到不同物理盘,用innodb_log_group_home_dir与datadir分离路径降低争用。
最后要建立监控闭环。用pt-diskstats或node_exporter采集磁盘await、svctm、util,与MySQL的Slave_delay和Innodb_os_log_fsyncs做关联。若调参后util从95%降到40%且延迟不增长,说明策略生效。切忌一次性改动过多参数,应每次只调整一个变量并观察二十四小时,才能定位真正有效的优化点,保障从库既低IO又具备崩溃恢复能力。