1.环境说明
OS:RedHat 6.2 x86_64
DB:MySQL 5.6.16
服务器:Vmware ESX
虚拟机资源: 2*6C,32G Mem,6G swap
2.问题现象
MySQL内存持续增加,最高时物理内存消耗28-29g,导致swap使用率100%,进而造成内存不足,系统自动kill mysql进程。
OS的syslog日志如下:
3.MySQL内存消耗过高分析与处理
MySQL的内存消耗分为:
1.会话级别的内存消耗:如sort_buffer_size等,每个会话都会开辟一个sort_buffer_size来进行排序操作
2.全局的内存消耗:例如:innodb_buffer_pool_size等,全局共享的内存段
其中170的数据库的全局内存消耗很稳定,没有出现增加的现象,那么会话级的内存消耗可能是一个主因。
关于会话级的内存消耗解释如下:
-
read_buffer_size, sort_buffer_size, read_rnd_buffer_size, tmp_table_size这些参数在需要的时候才分配,操作后释放。
-
这些会话级的内存,不管使用多少都分配该size的值,即使实际需要远远小于这些size。
-
每个线程可能会不止一次需要分配buffer,例如子查询,每层都需要有自己的read_buffer,sort_buffer, tmp_table_size 等
-
找到每次内存消耗峰值是不切实际的,因此我的这些建议可以用来衡量一下你实际修改一些变量值产生的反应,例如把 sort_buffer_size 从1MB增加到4MB并且在 max_connections 为 1000 的情况下,内存消耗增长峰值并不是你所计算的3000MB而是30MB。
mysql内存计算器:
参数调整如上。
参数调整后,MySQL的内存消耗一直持续在19-21g,没有出现明显的增加。
PS:
我们在测试的过程中也发现一个奇怪的问题:停止所有应用的会话,会话数从1000左右将至12,但实际内存并没有释放。
具体原因未知,还有待以后进行深入分析
4.MySQL内存经常被置换到swap问题分析及处理
虽然MySQL的物理内存不再持续增加,虽然cached有5g,但是已经开始在写swap了:
查看:cat /proc/$(pid)/smaps,查看mysqld的进程14908的内存,其中swap空间基本全部为mysql进程占用。
为什么还有5g的cache,为什么还用swap呢?
处理方法:
1.调整内存分配优先级:
-
#临时调整方法:
-
echo 0 > /proc/sys/vm/swappiness
-
#永久调整方法:
-
vi /etc/sysctl.conf 添加
-
vm.swappiness = 0
-
sysctl -p #使生效
vm.swappiness是操作系统控制物理内存交换出去的策略。它允许的值是一个百分比的值,最小为0,最大运行100,该值默认为60。vm.swappiness设置为0表示尽量少swap,100表示尽量将inactive的内存页交换出去。具体的来说当内存基本用满的时候,系统会根据”vm.swappiness“这个参数来判断是把内存中很少用到的inactive内存交换出去,还是释放数据的cache。cache中缓存着从磁盘读出来的数据,根据程序的局部性原理,这些数据有可能在接下来又要被读取;inactive 内存顾名思义,就是那些被应用程序映射着,但是“长时间”不用的内存。
查看inactive内存:
-
[root@sssjfxptmysql1~]#vmstat-an1
-
procs-----------memory-------------swap-------io------system-------cpu-----
-
r b swpd free inact active si so bi bo in cs us sy id wa st
-
3 0 0208796730275224661596 0 1 692 268 0 023 370 5 0
-
2 0 0207508730364824661564 0 0 1604 2408617643912 184 2 0
-
0 0 0207432730454424661696 0 0 232 51635593111 4 195 0 0
-
0 0 0206936730471224661800 0 0 128 6042283653 4 095 0 0
-
3 0 0205964730479224663200 0 0 1732 1169449720112 284 3 0
-
3 0 0203616730726024663540 0 0 2716 248159531273820 373 4 0
2. 修改MySQL的配置参数innodb_flush_method,开启O_DIRECT模式。
这种情况下,InnoDB的buffer pool会直接绕过文件系统cache来访问磁盘,但是redo log依旧会使用文件系统cache。值得注意的是,Redo log是覆写模式的,即使使用了文件系统的cache,也不会占用太多。
3、添加MySQL的配置参数memlock
这个参数会强迫mysqld进程的地址空间一直被锁定在物理内存上,对于os来说是非常霸道的一个要求。必须要用root帐号来启动MySQL才能生效。
其中2和3的方法,先不建议使用,后续再继续观察。
5.后续-关于CPU的NUMA架构对SWAP的影响及处理
参考:
2.The MySQL “swap insanity” problem and the effects of the NUMA architecture
具体numa和smp的架构就不介绍了。
NUMA的内存分配策略有localalloc、preferred、membind、interleave。localalloc规定进程从当前node上请求分配内存;而preferred比较宽松地指定了一个推荐的node来获取内存,如果被推荐的node上没有足够内存,进程可以尝试别的node。membind可以指定若干个node,进程只能从这些指定的node上请求分配内存。interleave规定进程从指定的若干个node上以RR算法交织地请求分配内存。
NUMA的内存分配策略对于进程(或线程)之间来说,并不是公平的。在现有的Redhat Linux中,localalloc是默认的NUMA内存分配策略,这个配置选项导致资源独占程序很容易将某个node的内存用尽。而当某个node的内存耗尽时,Linux又刚好将这个node分配给了某个需要消耗大量内存的进程(或线程),swap就妥妥地产生了。尽管此时还有很多page cache可以释放,甚至还有很多的free内存。
MySQL采用线程技术,NUMA对MySQL的支持并不太好,如果单机上只运行一个MySQL实例,且没有其他大型的应用程序,则NUMA与SMP的架构对MySQL并没有多大区别。因此解决方案一般有2种方法:
-
关闭numa特性
-
启动mysqld程序时,设置交叉内存分配策略
1.关闭numa特性
关闭NUMA特性的方法,分别有:可以从BIOS,操作系统关闭这个特性。
a) 由于各种BIOS类型的区别,如何关闭NUMA千差万别,我们这里就不具体展示怎么设置了。
b) 在操作系统中关闭,可以直接在/etc/grub.conf的kernel行最后添加numa=off
最好的方式还是在BOIS上进行关闭
2.启动mysql程序时,设置交叉内存分配策略
-
vi $MYSQL_HOME/bin/mysqld_safe
-
#找到下面这段shell:
-
cmd="`mysqld_ld_preload_text`$NOHUP_NICENESS"
-
#在这行下面添加:
-
cmd="/usr/bin/numactl --interleave all $cmd"
说明:实时计算平台并未做此调整
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/25704976/viewspace-1319609/
,如需转载,请注明出处,否则将追究法律责任。