[转帖]MySQL 内存泄露怎样检查

mysql,内存,泄露,怎样,检查 · 浏览次数 : 0

小编点评

**内存泄露分析方法** **1.参数设置和设计** * 尽量好合理的设计,避免内存泄露。 * 使用适当的设置参数,优化性能。 * 优化内存分配方法,例如使用mmap。 **2.ps库分析** * 使用ps库,分析进程的内存使用情况。 * 可以使用pmap工具,查看进程的内存映像信息。 * 使用dirty等变量,了解内存泄露的具体情况。 **3.pmap工具** * 使用pmap工具,分析进程的内存分配情况。 * 可以使用pmap工具,导出内存文件。 * 使用writeable/private等变量,了解进程所占用的私有地址空间大小。 **4.总结** * 通过参数设置,设计,ps库分析,pmap工具,总结出内存泄露的原因。 * 优化性能,设置参数,使用mmap等方法优化内存分配。 * 使用pmap工具导出内存文件,进行内存分析。 * 使用writeable/private等变量,了解进程所占用的私有地址空间大小。 * 进行版本升级,如果存在内存泄露问题,可以使用版本升级。

正文

MySQ使用内存上升90%!在运维过程中50%的几率,会碰到这样的问题。算是比较普遍的现象。
MySQL内存使用率过高,有诸多原因。普遍的情况是因为使用不当导致的,还有mysql本身的缺陷的导致的。到底是那方面的问题,那就需要一个一个进行排查。

下面介绍排查思路:

1.参数配置需要确认。是否内存设置合理.

MySQL内存分为全局和线程级:

  • 全局内存(如:innodb_buffer_pool_size,key_buffer_size,innodb_log_buffer_size)
    • 线程级内存:(如:thread,read,sort,join,tmp 等)只是在需要的时候才分配,并且在那些操作做完之后就释放)。
    • 线程级内存:线程缓存每个连接到MySQL服务器的线程都需要有自己的缓冲。默认分配thread_stack(256K,512k),空闲时这些内存是默认使用,处置之外网络缓存,还有表缓存等。大致评估会在1M~3M这样的情况。
      可通过pmap观察内存变化:
      image.png
  1. mysql> SELECT @@query_cache_size,
  2. @@key_buffer_size,
  3. @@innodb_buffer_pool_size ,
  4. @@innodb_log_buffer_size ,
  5. @@tmp_table_size ,
  6. @@read_buffer_size,
  7. @@sort_buffer_size,
  8. @@join_buffer_size ,
  9. @@read_rnd_buffer_size,
  10. @@binlog_cache_size,
  11. @@thread_stack,
  12. (SELECT COUNT(host) FROM information_schema.processlist where command<>'Sleep')\G;
  13. *************************** 1. row ***************************
  14. @@query_cache_size:1048576
  15. @@key_buffer_size:8388608
  16. @@innodb_buffer_pool_size:268435456
  17. @@innodb_log_buffer_size:8388608
  18. @@tmp_table_size:16777216
  19. @@read_buffer_size:131072
  20. @@sort_buffer_size:1048576
  21. @@join_buffer_size:1048576
  22. @@read_rnd_buffer_size:2097152
  23. @@binlog_cache_size:8388608
  24. @@thread_stack:524288
  25. (select count(host) from information_schema.processlist where command<>'Sleep'): 1

备注:query_cache_size 8.0版本已经废弃掉了

2.存储过程&函数&触发器&视图

目前积累的使用经验中, 存储过程&函数&触发器&视图 在MySQL场景下不适合的。性能又不好,又容易发现内存不释放的问题。所以建议尽量避免。

  • 存储过程&函数

MySQL 5.7

mysql> SELECT db,type,count(*) FROM mysql.proc WHERE db not in ('mysql','information_schema','performance_schema','sys') GROUP BY db, type;

MySQL 8.0

mysql> SELECT Routine_schema, Routine_type FROM information_schema.Routines WHERE Routine_schema not in ('mysql','information_schema','performance_schema','sys') GROUP BY Routine_schema, Routine_type;

  • 视图
mysql> SELECT TABLE_SCHEMA , COUNT(TABLE_NAME) FROM information_schema.VIEWS WHERE TABLE_SCHEMA not in ('mysql','information_schema','performance_schema','sys') GROUP BY TABLE_SCHEMA ;
  • 触发器
mysql> SELECT TRIGGER_SCHEMA, count(*) FROM information_schema.triggers WHERE TRIGGER_SCHEMA not in ('mysql','information_schema','performance_schema','sys') GROUP BY TRIGGER_SCHEMA;

上面通过mysql配置参数和设计层面检查了是否有可能内存泄露的问题。下面看看怎样分析实际使用的内存情况。

3.系统库统计查询

总内存使用:

mysql> SELECT SUM(CAST(replace(current_alloc,'MiB','') as DECIMAL(10, 2)) ) FROM sys.memory_global_by_current_bytes WHERE current_alloc like '%MiB%';

分事件统计内存

mysql> SELECT event_name, SUM(CAST(replace(current_alloc,'MiB','') as DECIMAL(10, 2)) ) FROM sys.memory_global_by_current_bytes WHERE current_alloc like '%MiB%' GROUP BY event_name ORDER BY SUM(CAST(replace(current_alloc,'MiB','') as DECIMAL(10, 2)) ) DESC ; mysql> SELECT event_name, sys.format_bytes(CURRENT_NUMBER_OF_BYTES_USED) FROM performance_schema.memory_summary_global_by_event_name ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 10;

账号级别统计

mysql> SELECT user,event_name,current_number_of_bytes_used/1024/1024 as MB_CURRENTLY_USED FROM performance_schema.memory_summary_by_account_by_event_name WHERE host<>"localhost" ORDER BY current_number_of_bytes_used DESC LIMIT 10;

备注:有必要统计用户级别内存,因为很多环境对接了第三方插件,模拟从库,这些插件容易内存不释放

线程对应sql 语句,内存使用统计

  1. SELECT thread_id, event_name, sys.format_bytes(CURRENT_NUMBER_OF_BYTES_USED) FROM performance_schema.memory_summary_by_thread_by_event_name ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 20;
  2. SELECT m.thread_id tid, m.user, esc.DIGEST_TEXT, m.current_allocated, m.total_allocated FROM sys.memory_by_thread_by_current_bytes m, performance_schema.events_statements_current esc WHERE m.`thread_id` = esc.THREAD_ID \G

打开所有内存性能监控,会影响性能。注意

 

#打开

UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'memory/%';

#关闭

UPDATE performance_schema.setup_instruments SET ENABLED = 'NO' WHERE NAME LIKE 'memory/%';

#查看使用

SELECT * FROM performance_schema.memory_summary_global_by_event_name WHERE EVENT_NAME LIKE 'memory/%' ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC;

系统表内存监控信息:

  1. select * from sys.x$memory_by_host_by_current_bytes;
  2. select * from sys.x$memory_by_thread_by_current_bytes;
  3. select * from sys.x$memory_by_user_by_current_bytes;
  4. select * from sys.x$memory_global_by_current_bytes;
  5. select * from sys.x$memory_global_total;
  6. select * from performance_schema.memory_summary_by_account_by_event_name;
  7. select * from performance_schema.memory_summary_by_host_by_event_name;
  8. select * from performance_schema.memory_summary_by_thread_by_event_name;
  9. select * from performance_schema.memory_summary_by_user_by_event_name;
  10. select * from performance_schema.memory_summary_global_by_event_name;

备注:找到对应问题事件或线程后,可以进行排查,解决内存高的问题。

4.系统工具查看内存

1)top命令

显示系统中各个进程的资源占用状况

  • Shift + m 键 查看内存排名实际使用内存情况,关注RES指标

2)free命令

free -h 命令显示系统内存的使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存

  • used 列显示已经被使用的物理内存和交换空间。
  • buff/cache 列显示被 buffer 和 cache 使用的物理内存大小。
  • available 列显示还可以被应用程序使用的物理内存大小。
  • Swap 行(第三行)是交换空间的使用情况。

3)ps命令

mysql相关进程使用内存情况

  1. shell > ps eo user,pid,vsz,rss $(pgrep -f 'mysqld')
  2. USER PID VSZ RSS
  3. root 215945 12960 2356
  4. mysql 217246 1291540 241824
  5. root 221056 12960 2428
  6. mysql 374243 1336924 408752

4)pmap 命令

pmap 是Linux调试及运维一个很好的工具。查看进程的内存映像信息

用法1:执行一段时间 记录数据变化,最少20个记录,下面22837是mysql pid

while true; do pmap -d  22837  | tail -1; sleep 2; done

用法2:linux 命令pmap mysql pid 导出内存 ,下面22837是mysql pid

pmap -X -p 22837 > /tmp/memmysql.txt

RSS 就是这个process 实际占用的物理内存。
Dirty: 脏页的字节数(包括共享和私有的)。
Mapping: 占用内存的文件、或[anon](分配的内存)、或[stack](堆栈)。
writeable/private 表示进程所占用的私有地址空间大小,也就是该进程实际使用的内存大小。

1.首先使用/top/free/ps在系统级确定是否有内存泄露。如有,可以从top输出确定哪一个process。
2.pmap工具是能帮助确定process是否有memory leak。确定memory leak的原则:
writeable/private (‘pmap –d’输出)如果在做重复的操作过程中一直保持稳定增长,那么一定有内存泄露。

总结

对于mysql内存泄露来说,

  • 从参数设置和设计上 尽量好合理
  • 需要通过ps库进行排查
  • linux工具进行进一步确认
  • 官方bug里 memory leak查找,是否存在修复的版本

以上排查里都没有找到原因,可以换下服务器或主从切换观察。也可以进行版本升级(代价不小)。
如:能提供一个实际环境,也可以一步一步进行调试,抓取内存变化,确定是什么导致内存泄露的问题。之后提交bug,让官方提供修复。
image.png

文章知识点与官方知识档案匹配,可进一步学习相关知识
MySQL入门技能树首页概览35197 人正在系统学习中

与[转帖]MySQL 内存泄露怎样检查相似的内容:

[转帖]MySQL 内存泄露怎样检查

MySQ使用内存上升90%!在运维过程中50%的几率,会碰到这样的问题。算是比较普遍的现象。 MySQL内存使用率过高,有诸多原因。普遍的情况是因为使用不当导致的,还有mysql本身的缺陷的导致的。到底是那方面的问题,那就需要一个一个进行排查。 下面介绍排查思路: 1.参数配置需要确认。是否内存设置

[转帖]Jemalloc及内存泄漏分析

https://zhuanlan.zhihu.com/p/138886684 不同层面的内存使用 Operating System 当程序在执行的时候, 可以通过ps, top等系统命令来预先发现内存泄漏的进程, 比如我们关注的是mysqld, 可以使用如下脚本来监控它的内存使用量. 这样能定位到可

【转帖】Mysql一张表可以存储多少数据

https://www.cnblogs.com/wenbochang/p/16723537.html Mysql一张表可以存储多少数据 在操作系统中,我们知道为了跟磁盘交互,内存也是分页的,一页大小4KB。同样的在MySQL中为了提高吞吐率,数据也是分页的,不过MySQL的数据页大小是16KB。(确

[转帖]ARM64 CentOS系统下MySQL使用jemalloc时的问题和解决方法

https://aijishu.com/a/1060000000321521 本文主要介绍在ARM64 CentOS系统下,MySQL使用jemalloc作为内存管理器时,内存占用问题的分析过程和解决方法。 Jemalloc 简介 Jemalloc是由Jason Evans在FreeBSD项目中引入

[转帖]Oracle、MySQL、PG是如何处理数据库“半页写”的问题的?

数据库“断页”是个很有意思的话题,目前任何数据库应该都绕不过去。我们知道数据库的块大小一般是8k、16k、32k,而操作系统块大小是4k,那么在数据库刷内存中的数据页到磁盘上的时候,就有可能中途遭遇类似操作系统异常断电而导致数据页部分写的情况,进而造成数据块损坏,数据块损坏对于某些数据库是致命的,可

[转帖]MySQL 8.0 Instant Add Column功能解析

https://zhuanlan.zhihu.com/p/408702204 概述 DDL(Data Definition Language)是数据库内部的对象进行创建、删除、修改的操作语言,主要包括:加减列、更改列类型、加减索引等类型。数据库的模式(schema)会随着业务的发展不断变化,如果没有

[转帖]Mysql之LSN和checkpoint和double write

https://www.jianshu.com/p/57a1dcf39b88 一直弄不清楚LSN和checkpoint的意思 个人理解:当要把buffer_pool里的脏页刷入磁盘的时候,会用checkpoint记录刷入内容,刷入到哪里了。防止下次忘记刷入内容,刷入到哪里了。checkpoint就是

[转帖]MySQL InnoDB存储引擎大观

https://baijiahao.baidu.com/s?id=1709263187856706948&wfr=spider&for=pc MySQL InnoDB 引擎现在广为使用,它提供了事务,行锁,日志等一系列特性,本文分析下 InnoDB的内部实现机制,MySQL 版本为 5.7.24,操

[转帖]MySQL快速备份表

https://www.cnblogs.com/JaxYoun/p/14264593.html 1、复制表结构及数据到新表 CREATE TABLE 新表 SELECT * FROM 旧表 这种方法会将oldtable中所有的内容都拷贝过来,当然我们可以用delete from newtable;来

【转帖】mysql一个索引块有多少指针_深刻理解MySQL系列之索引

索引 查找一条数据的过程 先看下InnoDB的逻辑存储结构:node 表空间:能够看作是InnoDB存储引擎逻辑结构的最高层,全部的数据都存放在表空间中。默认有个共享表空间ibdata1。若是启用innodb_file_per_table参数,须要注意每张表的表空间内存放的只是数据、索引和插入缓冲B