MySQLOOM(内存溢出)的解决思路
OOM全称"Out Of Memory",即内存溢出。
内存溢出已经是软件开发历史上存在了近40年的“⽼⼤难”问题。在操作系统上运⾏各种软件时,软件所需申请的内存远远超出了物理内存所承受的⼤⼩,就叫内存溢出。
内存溢出产⽣原因多种多样,当内存严重不⾜时,内核有两种选择:
1. 直接panic
2. 杀掉部分进程,释放⼀些内核。
mysql是什么系统⼤部分情况下,会杀掉导致OOM的进程,然后系统恢复。通常我们会添加对内存的监控报警,例如:当memory或swap使⽤超过90%时,触发报警通知,需要及时介⼊排查。
如果已经出现OOM,则可以通过dmesg命令查看,CentOS7版本以上⽀持 -T选项,能将时间戳转成时间格式,⽅便查看具体时间:
[root@localhost ~]# free -m total used free shared buffers cachedMem: 128937 128527 409 1 166 1279-/+ buffers/cache: 127081 1855Swap: 16383 16252 131
通过⽇志可以看出哪些进程、占⽤多少内存等信息,并会Kill掉占⽤内存较⼤的进程。
内存问题的排查思路
⼀、操作系统内存检查
已MySQL为例,OOM后,mysqld进程被Killed,内存会被释放。mysqld_safe安全进程会将mysqld拉起,此时查看到的系统内存会是⼀个正常值。如果内存使⽤很⾼,但还未OOM,系统内存使⽤情况可
能为下⾯情况:
[root@localhost ~]# free -m total used free shared buffers cachedMem: 128937 128527 409 1 166 1279-/+ buffers/cache: 127081 1855Swap: 16383 16252 131
可以看出此时的内存使⽤已经很⾼了,物理内存和swap虚拟内存⼏乎都被⽤完,buffers和cached也不多,随时可能出现OOM的情况。
⾸先,通过top命名查看占⽤内存最⼤的进程:
shift+o可以选择排序⽅式,n代表%MEM。
[root@localhost ~]# topMem: 132031556k total, 131418864k used, 612692k free, 212104k buffersSwap: 16777212k total, 0k used, 16777212k free, 14648144k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND14920 mysql 20 0 125g 109g 6164 S 6.6 87.0 27357:08 mysqld
spwm调制波是什么波可以看出mysqld进程占⽤内存最⼤,也可以这样查:
[root@localhost ~]# ps -e -o 'pid,comm,args,pcpu,rsz,vsz,stime,user,uid' | grep -E 'PID|mysql' |grep -v grep PID COMMAND COMMAND %CPU RSZ VSZ STIME USER UID25339 mysqld /export/servers/mysql/bin/m 9.4 115001324 130738976 2017 mys RSZ为进程占⽤私有内存⼤⼩,单位Kb。
VSZ为映射的虚拟内存⼤⼩,单位Kb。
通过RSZ/total 也可以算出占⽤总内存⽐例。
⼆、查看给mysql分配的内存
mysql内部主要内存可通过下⾯语句查出:
MYSQL >SET @giga_bytes = 1024*1024*1024;SELECT (@@key_buffer_size + @@query_cache_size + @@tmp_table_size + @@innodb_buffer_pool_size + @@innodb_additional_mem_pool_size + @@innodb_log_buffer_size + (select count(HOST) from in 每个参数配置⼤⼩:
*************************** 1. row *************************** @@key_buffer_size: 67108864 @@query_cache_size: 0 @@tmp_table_size: 268435456 @@innodb_buffer_pool_size: 38654705664@@innodb_additional_mem_pool_size: 134217728 @@innodb 每个参数配置说明:
innodb_buffer_pool_size占⽤内存最⼤的参数
innodb_additional_mem_pool_size额外内存,mysql5.7以后移除
innodb_log_buffer_size重做⽇志缓存⼤⼩
key_buffer_size只⽤于MyISAM引擎,不需要太⼤
tmp_table_size临时表缓存⼤⼩
query_cache_size查询缓存,建议关闭
max_connections最⼤连接数
read_buffer_size read_rnd_buffer_size sort_buffer_size join_buffer_size binlog_cache_size thread_stack 这些参数都跟线程有关,所占内存为这些参数的和*最⼤连接数。连接数越多占⽤内存也就越多,建议不超过512K,binlog_cache_size采⽤系统默认32K,thread_stack默认256K即可
需要给mysql分配多⼤内存,直接跟以上参数有关。太⼤会导致内存不⾜,太⼩会影响性能,如何分配合理值,还需根据业务情况来定。但业务场景较多,每个业务配置都不⼀样,会造成运维成本较⾼。
所以能定制出⼀套适⽤于绝⼤多数场景的配置模板就可以了。
1、如果mysql分配的内存⽐系统内存⼤
⽐如系统内存128G,mysql分配的内存已经⼤于128G,但是系统本⾝和其它程序也需要内存,甚⾄mysqldump同样需要内存,所以这样就很容易造成系统内存不⾜,从⽽导致OOM。这时我们要查出哪
些参数设置⽐较⼤,适当降低内存分配。
innodb_buffer_pool在mysql中占有最⼤内存,将innodb_buffer_pool_size调⼩可以有效降低OOM问题。但如果设置太⼩会导致内存刷脏页频率增加,IO增多,从⽽降低性能。通常我们认为
innodb_buffer_pool_size为系统内存的60%~75%最优。
查看buffer_pool的使⽤情况:
MYSQL >select POOL_ID,POOL_SIZE,FREE_BUFFERS,DATABASE_PAGES,OLD_DATABASE_PAGES,MODIFIED_DATABASE_PAGES,PAGES_MADE_YOUNG,PAGES_NOT_MADE_YOUNG from information_schema.INNODB_BUFFER_POOL_STAT 可以看出buffer_pool分了3个实例,POOL_SIZE为每个实例⼤⼩,这⾥为页个数,我们知道mysql页的默认⼤⼩为16K,所以单个实例的真正⼤⼩为611669*16K,5.6以后要求FREE_BUFFERS⾄少保留
1024个页,少于1024个页时会强制刷脏数据,后⾯的值可以看出脏页情况。另外如果PAGES_MADE_YOUNG远⼤于PAGES_NOT_MADE_YOUNG页数,那么此时内存使⽤就可能⽐较⼤,可以适当
自己搭建服务器的聊天软件降低innodb_buffer_pool_size⼤⼩。
另⼀篇⽂章也有对buffer_pool的介绍:⼀条命令解读InnoDB存储引擎—show engine innodb status
如果innodb_buffer_pool_size不是很⼤,但内存还是很⾼,也可能是由于并发线程太多导致,需要确认是不是应⽤异常,还是需要调整max_connections最⼤连接。如果连接太多,每个连接也会占⽤独
⽴的内存,read、sort、join缓存都是session级别,连接越多需要内存就越多,所以这些参数也不能设置太⼤。
需要注意的是⼀些参数不⽀持动态修改,只能先修改配置⽂件然后重启mysql才能⽣效,所以在mysql启动之前,⼀定要把参数值确认好。
printf python2、如果mysql分配的内存⽐系统内存⼩
如果mysql参数设置都⽐较合理,但是仍然出现oom,那么可能是由于mysql在系统层⾯所需内存不⾜导致,因为mysql读取表时,如果同时有多个session引⽤⼀个表则会创建多个表对象,这样虽然减少
了内部表锁的争⽤,但是会加⼤内存使⽤量。
⾸先,可以通过lsof -p pid查看进程打开的系统⽂件数,pid为mysqld的进程号。
[root@localhost ~]# ps -ef | grep mysqld[root@localhost ~]# lsof -p 3455COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEmysqld 30012 mysql cwd DIR 8,3 12288 58982404 /mysql/datamysqld 30012 mysql mem REG 8,1 599392 272082 /查看mysql服务打开⽂件数限制:
MySQL >show global variables like 'open_files_limit';+------------------+-------+| Variable_name | Value |+------------------+-------+| open_files_limit | 65535 |+------------------+-------+
查看操作系统打开⽂件数限制:
[root@localhost ~]# ulimit -amax memory size (kbytes, -m) unlimitedopen files (-n) 65535
如果此时打开的⽂件很多,内存也会占⽤很多。
其次,还需看⼀下table_open_cache,当打开⼀个表后会把这个表的⽂件描述符缓存下来。
MYSQL >show global variables like 'table_open_cache';+------------------+-------+| Variable_name | Value |+------------------+-------+| table_open_cache | 16384 |+------------------+-------+MYSQL >show global status like '%open%tables%';+------------------------+--------+| Variabl
通过以上两个值来判断 table_open_cache 是否到达瓶颈。
当缓存中的值open_tables 临近到了 table_open_cache 值的时候,说明表缓存池快要满了,但Opened_tables 还在⼀直有新的增长,这说明还有很多未被缓存的表。
⽤show open tables from schema命令,可以查看table_open_cache中缓存的表,重复打开的表仅显⽰⼀个
MYSQL >show open tables from sysbenchtest;+--------------+----------+--------+-------------+| Database | Table | In_use | Name_locked |+--------------+----------+--------+-------------+| sysbenchtest | sbtest1 | 1 | 0 || sysbenchtest | sbtest2 | 0 | 0 || sysbenchtest | sbtest3 | In_use显⽰当前正在使⽤此表的线程数,如果⼤于0也意味着此表被锁。
Name_locked只适⽤于DROP和RENAME,在执⾏DROP或RENAME时,table_open_cache中的表⽂件描述符会被移除,所以不会看到除0以外的其他值。
⼀般在库表⽐较多的情况下(分库分表)很容易出现内存占⽤较⼤的情况。如果要解决根源,还是需要对库表进⾏拆分。
3、MYSQL内部其他内存
自己的店铺如何弄小程序information_schema下的表都使⽤的都是MEMORY存储引擎,数据只在内存中保留,启动时加载,关闭后释放。
查看除系统库外是否有MEMORY引擎表:
MySQL >select * from information_schema.tables where engine='MEMORY' and TABLE_SCHEMA !='information_schema';
如果业务有使⽤MEMORY存储引擎的,尽量改成innodb引擎。
4、MYSQL事件内存指标
从MySQL5.7开始,在performance_schema中会记录内存分配。
查看哪些指标启动了内存收集功能:
redis使用手册MySQL >select * from performance_schema.setup_instruments where NAME LIKE 'memory/%';
启动需要收集内存的指标:
MySQL >UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'memory/%';
指标的内存收集结果会汇总到到sys库下的视图中:
MySQL root@[sys]>show tables like 'memory%';+-----------------------------------+| Tables_in_sys (memory%) |+-----------------------------------+| memory_by_host_by_current_bytes || memory_by_thread_by_current_bytes || memory_by_user_by_current_bytes || memory_这些视图总结了内存使⽤情况,按事件类型分组,默认降序排列:
MySQL >select event_name,current_count,current_alloc,high_alloc _global_by_current_bytes where current_count > 0;+--------------------------------------------------------------------------------+---------------+---------------+-------------+| event_name | curre 总结:
通过以上排查能⼤体知道哪些占⽤内存较多,针对内存占⽤较多的地⽅再做具体优化。正像⽂章开头所说的,内存溢出已经是软件开发历史上存在了近40年的“⽼⼤难”问题,更何况数据库环境更加复
杂,SQL语法、数据类型、数据⼤⼩等这些因素都与内存有关,所以在设计使⽤上更要多想内存溢出问题。
以上就是MySQL OOM(内存溢出)的解决思路的详细内容,更多关于MySQL OOM(内存溢出)的解决的资料请关注其它相关⽂章!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论