mysql内存使用过高排查

一、介绍
mysql 内存使用一般主要有buffer pool(主要),Server 层的的 Thread Cache、BinLog Cache、Sort Buffer、Join Buffer 等线程缓存,这类缓存非常驻内存,往往会随着连接关闭而释放,外加临时表(tmp_table_size)等。如果内存过高,可以从这些方面排查

注意:如果短时间内定位不到原因,但是mysql内存又在一直上升,很有可能OOM,可以通过重启实例或者是主从切换等应急操作来及时止损

二、排查过程
2.1、检查 buffer pool的值
buffer pool 是常驻内存,用完不会释放,一般给多少用多少,所以这个值不能超过宿主机的物理内存,一般给到60%到80%,
如果内存使用率过高且一直不下降,首先检查下是否buffer pool 设置不合理,该值设置过高还会有OOM的风险。
2.2、检查qps是否上升和复杂sql
查看监控 确认流量是否发生了变化、业务是否上线了新的 SQL。
如果业务流量突增,则可能导致内存使用率上升。比如上线了复杂sql,有join语句和order by 语句等。
还有sql是否产生了临时表,内存临时表大小受到参数 tmp_table_size 和 max_heap_table_size 限制,超过限制后将转化为磁盘临时表。如果瞬间有大量的连接创建大量的临时表,可能会造成内存突增。

如果有以上情况,可以使用show processlist;找到对应的sql,跟研发沟通后kill掉等措施来解决。
或者临时调小join buffer,sort buffer,tmp_table_size等参数值,但是这可能会影响sql执行效率,谨慎操作
2.3、检查是否有多语句
MySQL 支持将多个 SQL 语句用英文分号(;)分隔,然后一起发给 MySQL,MySQL 会逐条处理 SQL,但是某些内存需要等到所有的 SQL 执行结束才释放。
采用这种 multiple statements 的发送方式时,如果一次性发送的 SQL 非常多,例如达到数百兆,SQL 实际执行过程中各种对象分配累积消耗的内存非常大,很有可能导致 MySQL 进程内存耗尽。除了multiple statements,bulk insert(一条 insert 语句批量插入多条记录)、框架工具生成的超长 SQL ,也会在网络协议和 sql parser 阶段分配较多内存,也需要重点关注。
一般场景下,如果存在大批量的 multiple statements 或者 bulk insert,网络流量会有突增,可以从网络流量监控,判断是否有这种现象。

解决办法:
如果遇到这种情况,一般是有导数操作,或者是有脚本在跑等等,可以找到研发询问然后让他们停止操作,或者是减少并发

2.4、连接数增加
由于 MySQL 会为每个连接分配内存,如果连接数增加,也会导致 MySQL 内存使用率上升。 查看监控项连接数这个指标,看看有没有增加,如果有,可以执行show processlist查看是否有过多的 非活跃连接数,释放这些空连接,也可以让研发使用线程池等来优化。
2.5、全文索引
全文索引需要占用大量的内存来处理索引数据,所以需要重点关注。但是一般mysql不建议使用全文索引,如果涉及到需要使用的建议换mongodb或es等数据库
2.6、结论
通常 InnoDB Buffer Pool 对内存的占用是最多的,而且是常驻内存,不会释放,其他的很多内存是在请求执行中动态分配和调整的,一般sql执行完会自己释放掉,所以如果内存占用没有持续上升到不可接受(一般90%以下都可接受),可以等sql执行完自己释放。 如果发现内存一直居高不下,从不释放,则在确定不是buffer pool占用的情况下,要考虑是否是因为mysql本身bug导致的内存泄漏等情况。
三、performance_schema排查内存使用情况
点击查看代码
为了更方便的排查内存问题,可以使用 performance_schema 的内存监控功能(5.6默认不开启,5.7之后默认开启)。开启 performance_schema 后,在 performance_schema 库中查询名字为 memory_summary 开头的表来得知内存使用情况,例如,全局维度的内存利用率分析表:memory_summary_global_by_event_name。
常见的查询:

SELECT EVENT_NAME, CURRENT_NUMBER_OF_BYTES_USED FROM performance_schema.memory_summary_global_by_event_name
    WHERE COUNT_ALLOC != 0 
       OR COUNT_FREE != 0
       OR SUM_NUMBER_OF_BYTES_ALLOC != 0 
       OR SUM_NUMBER_OF_BYTES_FREE != 0 
       OR LOW_COUNT_USED != 0 
       OR CURRENT_COUNT_USED != 0 
       OR HIGH_COUNT_USED != 0 
       OR LOW_NUMBER_OF_BYTES_USED != 0 
       OR CURRENT_NUMBER_OF_BYTES_USED != 0 
       OR HIGH_NUMBER_OF_BYTES_USED != 0 
    ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC
    LIMIT 10;
posted @ 2025-06-19 11:03  有形无形  阅读(358)  评论(0)    收藏  举报