InnoDB缓冲池大小(innodb_buffer_pool_size)是解决从库磁盘I/O高的首要参数,建议设为物理内存的50%–70%,命中率低于99%时必须调大;同时关闭从库binlog和general_log,并合理限制sort_buffer_size与tmp_table_size以避免临时表落盘。

从库磁盘I/O高直接拖慢SQL线程回放
从库磁盘I/O高不是“现象”,而是SQL线程卡在刷脏页、写临时表或刷relay log上的明确信号。它会让Seconds_Behind_Master持续上涨,即使网络和主库都正常。根本原因不是“磁盘慢”,而是MySQL被迫频繁落盘——比如innodb_buffer_pool_size太小、sort_buffer_size不足、或tmp_table_size被突破,导致原本该在内存里完成的操作全挤到磁盘上。
检查并调大innodb_buffer_pool_size
这是最常被低估的瓶颈点。如果Innodb_buffer_pool_read_requests与Innodb_buffer_pool_reads算出的命中率低于99%,说明大量读操作正在穿透缓存直奔磁盘。
- 查当前值:
SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; - 查命中率:
SELECT (Innodb_buffer_pool_read_requests - Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests AS hit_rate FROM information_schema.GLOBAL_STATUS; - 调大建议:设为物理内存的50%–70%,但不能超过
free -h显示的可用内存下限;调整后需重启MySQL(注意:在线扩容仅支持MySQL 5.7.5+且需满足条件)
关闭从库binlog和general_log
从库若不承担级联复制或审计需求,开启log_bin或general_log纯属增加无谓I/O负担。尤其general_log会把每条语句都写盘,高并发下极易打满磁盘带宽。
- 确认状态:
SHOW VARIABLES LIKE 'log_bin';、SHOW VARIABLES LIKE 'general_log'; - 临时关闭:
SET GLOBAL log_bin = OFF;(需skip-log-bin写入配置文件才永久生效) - 永久关闭:在从库
my.cnf中注释或删除log_bin、general_log相关行,重启服务
避免从库执行ORDER BY/GROUP BY溢出内存
从库SQL线程回放时遇到ORDER BY或GROUP BY,若结果集超过sort_buffer_size或tmp_table_size,就会把临时数据写进磁盘临时表——这在高并发批量更新场景下非常致命。
- 查当前设置:
SHOW VARIABLES LIKE 'sort_buffer_size';、SHOW VARIABLES LIKE 'tmp_table_size'; - 合理上限:单次排序/分组通常不超过64M,可设为
sort_buffer_size = 4M、tmp_table_size = 64M(注意:过大会导致每个连接独占内存,反而引发OOM) - 更治本的做法:在主库就避免产生需要大排序的SQL,比如用覆盖索引消除
Using filesort,或拆分大范围UPDATE ... ORDER BY
从库磁盘I/O高背后往往藏着多个叠加问题:buffer pool不够、临时表失控、日志冗余、甚至硬件本身是HDD。单独调一个参数很难见效,得按“先看命中率→再关冗余日志→最后控排序内存”这个顺序动手,否则容易调了sort_buffer_size却发现90%的I/O其实来自buffer pool反复刷脏页。


















