从库CPU打满主因是SQL线程重放瓶颈或配置失当,需先确认SQL线程是否高负载,再检查并行复制配置、关闭冗余功能并定位锁冲突。

从库CPU打满,90%以上情况和主库无关,问题就出在从库自身重放逻辑或配置失当——不是SQL慢,而是“重放太用力”或者“边重放边被查”。盲目调大 innodb_buffer_pool_size 或杀线程,往往压不住,甚至让复制延迟更严重。
确认是不是SQL线程(SQL Thread)真正在吃CPU
从库CPU高,第一件事不是看慢查询,而是确认“谁在干活”:是IO线程(接收binlog)还是SQL线程(执行relay log)?
- 执行
SHOW SLAVE STATUS\G,重点看Slave_SQL_Running_State字段:如果显示Reading event from the relay log或Executing event,且持续时间长,说明SQL线程卡在某条语句上 - 用
top -Hp $(pgrep mysqld)查线程级CPU,再把高占用线程ID转16进制,去performance_schema.threads里查PROCESSLIST_ID,确认是否对应system_user为slave_sql - 如果
%sy(内核态CPU)异常高,或cs(上下文切换) > 10k/s,大概率是并发重放冲突或锁等待,不是单条SQL的问题
检查并行复制是否实际生效
MySQL 5.7+ 支持 slave_parallel_workers > 0,但默认不等于真正并行——很多场景下仍退化为单线程重放。
- 查
SHOW VARIABLES LIKE 'slave_parallel_type':必须是LOGICAL_CLOCK才支持按事务分组并行;若为DATABASE,则跨库事务仍串行 - 查
SHOW STATUS LIKE 'Slave_running'和Seconds_Behind_Master:如果延迟一直为0但CPU高,说明重放本身吃资源;如果延迟飙升+CPU高,说明重放不过来 - 检查主库是否开了
binlog_transaction_dependency_tracking = WRITESET(推荐),否则从库无法有效拆分事务依赖,slave_parallel_workers形同虚设
定位“假慢实卡”的重放瓶颈SQL
从库上跑 EXPLAIN 没用——你看到的是当前SQL的执行计划,但重放时可能因缺失统计信息、元数据锁、或隐式锁升级导致行为不同。
- 抓正在重放的SQL:查
performance_schema.events_statements_current,过滤THREAD_ID对应slave_sql线程,看SQL_TEXT和TIMER_WAIT - 重点关注
STATE = 'executing'且TIMER_WAIT持续增长的语句,尤其是含UPDATE ... WHERE、DELETE ... LIMIT、或INSERT ... SELECT的——这类语句在从库容易因索引缺失或锁粒度变大而卡住 - 别信
SHOW PROCESSLIST里的INFO:它可能只显示前100字符,用SELECT SQL_TEXT FROM performance_schema.events_statements_current WHERE THREAD_ID = ?拿完整SQL
关掉从库上不该开的功能
从库不是只读就安全——有些功能开着等于给重放加负重。
- 强制关闭
innodb_stats_on_metadata = OFF:否则每次应用连上来查information_schema.TABLES都触发统计更新,大表直接拖垮SQL线程 - 设
skip_log_bin = ON(仅限纯从库):避免从库自己又写binlog,多一层日志刷盘和锁开销 - 禁用查询缓存(
query_cache_type = 0):MySQL 5.7仍存在,QPS稍高就会因缓存锁引发争用,尤其在重放+查询混合场景 - 审计日志(
audit_log_policy)非必要一律设为NONE:每条重放SQL额外序列化+落盘,CPU白烧
真正难处理的,是从库被业务方当作“只读备库”却跑着高频 SELECT ... FOR UPDATE 或隐式事务,导致重放线程反复等锁。这种问题不会出现在 SHOW SLAVE STATUS 里,得靠 performance_schema.data_locks 和 data_lock_waits 实时抓——但一旦出现,就得协调业务改访问模式,不是DBA调参能解决的。


















