从库cpu高主因是被业务误连或执行低效查询,而非复制延迟本身;其次因重放binlog时缺失主库的查询缓存、预编译优化等,导致相同sql在从库解析与执行开销更大,叠加并行回放争抢、刷盘压力及统计信息不准等因素共同推高cpu。

从库CPU高,八成不是复制延迟本身导致的,而是从库在“额外干活”——比如被业务误连、执行了本不该它跑的查询,或者重放主库发来的低效语句时放大了CPU消耗。
为什么从库CPU会比主库还高?
主库写多读少,从库却常被当成只读实例混用;更隐蔽的是,主库上可能有查询缓存或预编译优化,而从库重放 binlog 时走的是原始执行路径,某些语句(如含函数、子查询、未参数化的 WHERE)在从库执行开销反而更大。另外,slave_parallel_workers 开太多,线程间争抢资源也会推高 CPU。
- 主库开了
query_cache_type=1,但从库默认关闭,同一条SELECT在从库每次都要重新解析+执行 - 主库用了 prepared statement,而 binlog 记录的是展开后的文本,从库无法复用执行计划
- 从库开启了
log_slave_updates,又做了级联复制,导致同一语句被反复解析和重放 -
innodb_flush_log_at_trx_commit=1+sync_binlog=1在从库也启用,刷盘压力叠加 CPU
确认是不是被业务直连了从库
别假设“我们没连从库”——查 information_schema.processlist 是最直接的方式。重点看 user 和 host 列是否来自业务服务 IP,且 Command 不是 Connect 或 Binlog Dump。
- 执行:
SELECT user, host, db, command, time, state, info FROM information_schema.processlist WHERE command != 'Sleep' AND user NOT IN ('system user', 'replication') - 如果返回大量
Query状态且info是业务 SQL(比如带ORDER BY created_at DESC LIMIT 20),基本坐实误连 - 临时阻断:在从库上
SET GLOBAL read_only = ON(注意这不影响复制线程),再配合防火墙封掉业务服务器到从库 3306 的非必要访问
检查复制重放阶段的 CPU 消耗点
从库 CPU 高,未必是慢查询日志里能抓到的——因为慢日志默认不记录 SQL Thread 执行的语句。得靠 SHOW PROFILE 或性能模式定位重放瓶颈。
- 先开启性能模式:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE 'events%' - 查当前 SQL Thread 的最近事件:
SELECT THREAD_ID, EVENT_NAME, TIMER_WAIT FROM performance_schema.events_statements_history_long WHERE THREAD_ID = (SELECT THREAD_ID FROM performance_schema.threads WHERE TYPE = 'FOREGROUND' AND PROCESSLIST_COMMAND = 'Query' AND PROCESSLIST_INFO LIKE 'SELECT%') ORDER BY TIMER_WAIT DESC LIMIT 5 - 常见高耗时项:
stage/sql/Sorting result(ORDER BY没走索引)、stage/sql/Creating sort index(内存排序溢出)、stage/innodb/row_lock_wait(虽然从库不该锁,但遇到INSERT ... ON DUPLICATE KEY UPDATE仍可能争锁) - 验证是否因统计信息不准导致优化器误判:对重放慢的表执行
ANALYZE TABLE table_name,尤其当主库刚批量导入过数据
避免从库成为“优化黑洞”的关键配置
很多调参看似合理,但在从库上反而加剧 CPU 压力。核心原则是:从库不参与决策,只忠实执行。
- 禁用查询缓存:
query_cache_type = 0(从库缓存命中率极低,维护成本反高) - 降低解析开销:
table_definition_cache和table_open_cache设为略高于实际活跃表数,避免频繁打开 frm 文件 - 限制并行回放强度:
slave_parallel_workers不宜超过 CPU 核心数的 70%,且确保slave_parallel_type = LOGICAL_CLOCK(而非 DATABASE) - 关闭不必要的日志:
log_output = 'FILE'+slow_query_log = OFF(除非你明确要分析从库自身查询) - 最关键的:
innodb_read_only = ON(MySQL 5.6.26+ 支持),强制 InnoDB 层跳过写保护检查,减少每行更新的判断逻辑
真正难处理的,是从库上跑着一个每天凌晨触发的报表查询,它本身不慢,但并发 20 跑起来就把 CPU 吃满——这种问题不会出现在 SHOW PROCESSLIST 的 top 10 里,得结合监控曲线和 performance_schema.events_statements_summary_by_digest 才能揪出来。别只盯着“复制线程”,先确认“谁在用从库”。











