MySQL主从复制线程CPU飙升的根源是IO_THREAD或SQL_THREAD在低效环节空转或重试:IO_THREAD卡在网络阻塞或relay log写入慢,SQL_THREAD因缺失索引、大事务或GTID校验开销过大而持续高负载。

MySQL主从复制线程为什么吃CPU
主从复制本身不直接导致CPU飙升,但IO_THREAD和SQL_THREAD在特定条件下会持续高负载运行,进而推高CPU使用率。根本原因不是“复制功能开销大”,而是线程被卡在某个低效环节里空转或重试。
IO_THREAD卡在Binlog Dump握手或网络阻塞
主库的Binlog Dump线程需持续向从库推送日志,一旦网络延迟高、丢包、或从库IO_THREAD接收慢(比如磁盘写入慢、relay log刷盘慢),主库该线程就会陷入等待+重试循环,表现为单核CPU持续100%占用,且SHOW PROCESSLIST中看到大量Master has sent all binlog to slave; waiting for more updates状态——这其实是“假空闲”,底层仍在轮询检测新事件。
- 检查主库网络:用
tcpdump -i any port 3306看是否有大量重传包 - 确认从库
IO_THREAD状态:SHOW SLAVE STATUS\G中Seconds_Behind_Master持续增长,且Slave_IO_Running: Yes但Slave_SQL_Running: Yes,说明IO线程在“收得慢”而非“收不到” - 临时缓解:在从库执行
STOP SLAVE IO_THREAD,观察主库CPU是否回落——若明显下降,问题就定位在IO链路
SQL_THREAD重放ROW格式日志时CPU暴涨
当binlog_format = ROW且表有大量更新时,SQL_THREAD要逐行解析INSERT/UPDATE/DELETE事件,并对每行做唯一键查找、索引维护、外键检查等操作。如果目标表缺少关键索引(如WHERE条件字段无索引),一次UPDATE可能触发全表扫描,CPU自然拉满。
- 查正在重放的语句:
SHOW SLAVE STATUS\G中Exec_Master_Log_Pos对应主库binlog位置,用mysqlbinlog --base64-output=DECODE-ROWS -v解析该位置附近事件,看是否含大事务或多行变更 - 检查从库表索引:对比主库,确认
WHERE、JOIN、ORDER BY涉及字段在从库是否都有索引——缺失一个就可能让SQL线程卡住 - 避免大事务:主库上禁止单个事务修改超1万行;若已发生,可考虑在从库临时设
slave_parallel_workers = 0,防止并行重放加剧锁争用
GTID模式下SQL_THREAD频繁查找事务边界
开启gtid_mode = ON后,SQL_THREAD每次执行前都要校验当前事务是否已在本机执行过(通过gtid_executed集合比对)。如果从库刚重启、或gtid_purged被误清空,它会回溯大量binlog文件做事务去重判断,CPU集中在字符串解析和集合查找上。
- 确认GTID状态异常:
SELECT @@gtid_executed;返回为空或远小于主库SELECT @@gtid_purged;,说明GTID集合不一致 - 不要手动
RESET MASTER:这会清空gtid_purged,强制SQL线程从头校验 - 安全跳过方式:仅当确认数据一致时,用
SET GTID_NEXT='xxx'; BEGIN; COMMIT;注入空事务跳过卡点,而非停掉SQL线程再START SLAVE
真正难排查的是SQL_THREAD在“看似正常执行”的状态下缓慢吞噬CPU——它不报错、不阻塞、Seconds_Behind_Master也不涨,但top里mysqld进程稳占70%以上。这时候必须抓取perf top -p $(pgrep mysqld)看热点函数,大概率落在row_search_for_mysql或dict_table_get里,指向索引缺失或表结构不一致。


















