从库innodb_buffer_pool_size配置与主库相同但实际使用更高,主因是从库读请求集中、无写入干扰导致缓存更满,而主库因持续写入引发页刷新和lru调整;此外并行复制积压、分析类查询触发per-connection缓冲区、relay log未消费事件驻留内存等隐性开销共同推高实际占用。

从库的 innodb_buffer_pool_size 配置和主库一样,但实际使用更高
这是最常见也最容易被忽略的错觉。从库的缓冲池大小配置值和主库相同,不代表它“用得少”。相反,从库往往更倾向于把缓冲池填满——因为它的读请求集中在复制回放后的热点查询(比如报表、监控拉取),且没有写入干扰,缓存命中率高、淘汰压力小。而主库有持续写入,会触发页刷新、LRU链调整、脏页刷盘等行为,反而让缓冲池看起来“没那么满”。
验证方式:SELECT ROUND(data_size/1024/1024/1024,2) AS used_gb FROM information_schema.innodb_buffer_pool_stats; 查看真实已用容量;再对比 SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; 看配置上限。如果从库 used_gb 接近上限、主库却只到 60%~70%,说明不是配置问题,而是使用模式差异。
- 从库默认不接受写,缓冲池不会因写放大产生额外碎片或预分配开销
- 主库的
innodb_buffer_pool_pages_dirty持续波动,从库几乎为 0,意味着内存更“干净”、更稳定地驻留数据页 - 若从库启用了
innodb_buffer_pool_load_at_startup,且上次 dump 的热页多,启动后会主动加载更多页到内存
slave_pending_jobs_size_max 和并行复制导致的隐性内存堆积
MySQL 5.6+ 启用并行复制(slave_parallel_workers > 0)后,从库会预取并暂存待执行的 relay log event。这些事件在应用前就已解包、解析、构造为内存中的事务对象,占用的是 slave_pending_jobs_size_max 控制的独立内存池,不计入 innodb_buffer_pool_size,但会显著抬高 VmRSS。
典型表现:从库 SHOW PROCESSLIST 中出现大量 Waiting for an event from Coordinator 状态线程,同时 SHOW STATUS LIKE 'Slave_received_transactions' 和 Slave_retried_transactions 差值较大,说明事件积压。
- 该参数默认值是 128MB(MySQL 5.7)、1GB(MySQL 8.0),但若网络延迟高或从库 SQL 线程处理慢,积压可能远超设定值
- 调低
slave_pending_jobs_size_max可缓解,但可能降低并行复制吞吐;建议结合slave_preserve_commit_order=ON和slave_parallel_type=LOGICAL_CLOCK一起评估 - 该内存无法通过
performance_schema.memory_summary_global_by_event_name直接归类,需靠/proc/`pidof mysqld`/status中的VmRSS与缓冲池实际用量做差值估算
从库上跑分析类查询,触发大临时表和排序缓冲区
主库通常只承担业务写入和简单读,而从库常被用于 BI 报表、导出、ETL 或 DBA 诊断查询。这类查询动辄扫描百万行、GROUP BY 多字段、ORDER BY 大结果集,会瞬间申请多个 sort_buffer_size、join_buffer_size、tmp_table_size 实例——每个连接独占一份,且不释放直到连接断开。
查证方式:SHOW FULL PROCESSLIST; 找出 State 为 Sorting result、Creating sort index、Copying to tmp table 的长时线程;再用 SELECT user, host, SUM(current_number_of_bytes_used)/1024/1024 AS MB FROM performance_schema.memory_summary_by_account_by_event_name GROUP BY user, host ORDER BY MB DESC LIMIT 5; 看是否某账号内存占比异常高。
- 临时表超过
tmp_table_size和max_heap_table_size(二者必须一致)会落盘,但磁盘临时表仍需先在内存建结构,且 MyISAM/InnoDB 临时引擎本身也有内存开销 - 从库未设
read_only=ON时,应用误连从库执行批量 INSERT/UPDATE,也会引发与主库不同的内存行为(如从库无 binlog cache 压力,但有更多 undo log 内存保留) - 避免在从库直接跑未加
LIMIT的SELECT COUNT(*)或全表JOIN,这类操作极易吃光 per-connection 缓冲区
复制延迟期间,relay log 解析与事件缓存持续驻留内存
当从库存在明显复制延迟(Seconds_Behind_Master > 30),IO 线程会持续从主库拉取 relay log 并写入本地文件,SQL 线程则滞后消费。此时,已读取但未执行的 relay log event 会保留在内存中等待解析——尤其是启用 GTID 或 row 格式时,event 解析后生成的 Rows_log_event 对象、Table_map_log_event 映射结构会长期驻留。
这种内存不体现在任何变量或 status 中,但会随延迟时间线性增长。重启 SQL 线程(STOP SLAVE; START SLAVE;)可清空,但治标不治本。
- 延迟越大,
Relay_Log_Space(SHOW SLAVE STATUS输出)越大,对应内存缓存也越多 - 检查
SHOW VARIABLES LIKE 'relay_log_info_repository';,若为FILE(而非TABLE),则 relay log 位置信息也依赖文件系统缓存,进一步增加 OS 层面的buff/cache占用 - 长期延迟往往伴随磁盘 IO 瓶颈(如从库磁盘慢、
sync_binlog=1主库压力传导),此时应优先优化从库 IO 能力,而非仅调内存参数
performance_schema 或变量里的内存:复制线程的 event 解析上下文、GTID set 的哈希结构、并行 worker 的事务队列、甚至 jemalloc 分配器本身的内部碎片。它们加起来可能占几 GB,但没有任何一个 SHOW 命令能直接告诉你“这 3.2GB 是谁占的”。所以别只盯着 innodb_buffer_pool_size —— 先确认 VmRSS 是否真高,再一层层剥开。











