CentOS 上 MySQL 内存占用过高的排查与优化
一 快速判断与定位
- 先看系统层占用:执行 top/htop,确认 mysqld 的 RES/VIRT 是否异常;再查看连接数:SHOW STATUS LIKE ‘Threads_connected’; 以及 InnoDB 缓冲池:SHOW VARIABLES LIKE ‘innodb_buffer_pool_size’; 这些能快速判断是连接过多还是缓冲池过大导致的内存压力。对于 MySQL 8,内存峰值常由 InnoDB 缓冲池与执行期临时内存共同决定。必要时可开启 performance_schema 的内存监控,定位具体分配来源:SELECT EVENT_NAME, CURRENT_NUMBER_OF_BYTES_USED FROM performance_schema.memory_summary_global_by_event_name ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 10; 若业务流量突增导致内存上升,应联动排查新上线的 SQL 或写入放大问题。
二 核心参数优化
- 调整 InnoDB 缓冲池:这是内存占用的大头。一般将 innodb_buffer_pool_size 设为物理内存的约 50%–70%(专用数据库、负载稳定时取高值;混部或有其他大内存服务时取低值)。例如:SET GLOBAL innodb_buffer_pool_size = 2147483648;(2GB)。若热数据占比小或查询时延不敏感,可适度下调,为执行期内存留出空间。
- 控制连接与线程开销:过高的 max_connections 会显著增加 per-thread 内存与连接管理开销。可按并发需求下调,例如:max_connections = 100;同时结合应用连接池(如 HikariCP、连接复用)避免“连接风暴”。
- 降低执行期内存分配:避免会话级过大的排序/连接/临时表缓冲(仅在会话需要时分配),例如适度降低 sort_buffer_size、join_buffer_size、read_buffer_size、read_rnd_buffer_size 等;仅在确有需要时再增大。
- 谨慎使用 performance_schema:在内存紧张且对监控时延不敏感的场景,可临时关闭 performance_schema(5.6 及以下需重启),以降低监控自身内存占用。
- 其他引擎与功能:若不使用 MyISAM,可将 key_buffer_size 调小;不需要复制/审计/二进制日志的场景,可关闭相应功能(如 skip-log-bin)以减少内存与 I/O 开销。
三 SQL 与索引治理
- 找出“吃内存”的 SQL:利用 performance_schema 或慢查询日志定位执行计划差、返回大结果集、大量排序/聚合/临时表、缺少合适索引的语句。
- 优化手段:为高频过滤/排序/关联列建立合适索引,避免 SELECT *,减少大偏移分页(用游标/键集分页),拆分大事务,必要时用 LIMIT 限制结果集。
- 限流与处置:对突发写入或异常 SQL 进行限流或 KILL SESSION,避免并发放大导致的内存激增。
四 配置示例与变更流程
五 何时扩容或回退
- 若已按上述优化后,内存使用仍长期接近或超过 90% 且出现抖动/OOM 风险,说明规格不足或流量增长超出当前配置承载能力,建议扩容实例规格(内存/CPU),或回退到更保守的参数组合并继续治理 SQL。