是磁盘io瓶颈,需通过iostat -dx 1确认%util > 95%且await > 20ms(ssd)或 > 50ms(nvme),常见原因包括relay log与数据共盘、云盘iops耗尽、raid写缓存禁用;优化措施含分离relay_log路径、调高innodb_io_capacity、设sync_relay_log=10000及限速备份任务。

从库relay log写入慢,iostat显示%util接近100%
这说明从库磁盘已饱和,relay log写不进去,IO线程卡在Writing to the relay log状态,后续SQL线程自然停摆。别只盯着Seconds_Behind_Master,先看iostat -dx 1输出里%util和await——如果%util > 95且await > 20ms(SSD)或> 50ms(NVMe),基本就是磁盘瓶颈。
常见诱因包括:relay log和innodb data目录混在一块机械盘上;云盘IOPS配额被主库binlog或备份任务吃光;RAID卡缓存策略禁用写缓存。
- 把
relay_log路径单独挂到高速盘:relay_log = /nvme/mysql/relay-bin,确保不与datadir或binlog共用物理设备 - 云环境务必核对IOPS配额:阿里云ESSD、AWS io2都支持按需提升,别用“通用型”实例跑从库
- 若用RAID卡,用
MegaCli -AdpBbuCmd -GetBbuStatus -aALL确认BBU健康,再执行MegaCli -SetCachedWrite -1 -aAll启用写缓存(注意搭配sync_relay_log=10000平衡安全与性能)
从库innodb刷盘跟不上relay log回放速度
SQL线程一边读relay log,一边往InnoDB写数据,但innodb_io_capacity设得太低,或者buffer pool频繁触发LRU淘汰导致大量脏页刷盘,就会拖慢回放。此时iostat可能显示svctm不高,但rrqm/s(读请求合并数)异常高,说明InnoDB在反复读取相同page。
- 调高
innodb_io_capacity:SSD设为2000,NVMe设为4000,必须配合innodb_io_capacity_max = 2 * innodb_io_capacity -
innodb_buffer_pool_size至少设为物理内存的70%,避免swap;若内存充足,可设为80%,减少物理读 - 禁用
innodb_adaptive_hash_index(MySQL 8.0+默认开启),它在高并发回放场景下反而引发latch争用
sync_relay_log配置不当放大IO压力
sync_relay_log控制relay log写入后是否强制刷盘。设为1(默认)时,每写一条event就fsync()一次,对机械盘是灾难;设为0则依赖OS缓存,断电可能丢relay log。生产环境真正合理的折中是10000——即每10000次写入刷一次盘,既降低IO频率,又保证丢失不超过1万个事务。
- 动态修改立即生效:
SET GLOBAL sync_relay_log = 10000 - 同时调大
sync_relay_log_info到10000,避免relay log info文件频繁刷盘 - 注意:该调整仅适用于从库,主库
sync_binlog仍建议保持1或1000(根据RPO要求)
备份任务与SQL线程抢IO资源
很多团队在从库跑mysqldump或xtrabackup时没加限速,导致FLUSH TABLES WITH READ LOCK阻塞SQL线程,或备份进程本身占满磁盘带宽。此时SHOW PROCESSLIST里会看到State为Waiting for table flush的长连接。
-
xtrabackup必须加--throttle=100(单位MB/s),并避开业务高峰 -
mysqldump加--single-transaction --skip-lock-tables,禁用LOCK TABLES - 更彻底的方案:把备份任务迁到专用备份节点,或使用
mysqlbackup的增量备份能力减少全量压力
真实延迟往往不是单一IO问题,而是磁盘队列、InnoDB刷盘、系统缓存、备份调度四层IO叠加的结果。改完参数后,一定要用iostat -dx 1盯住r/s、w/s、await三组数值变化,而不是只看Seconds_Behind_Master是否归零。











