这个标题很吸引眼球实际上内容也应该很好玩. 问题的产生是近我们在各个数据库进行数据库安装规范的事情,而在规范后,安装的台机器,进行压测就惨遭崩溃.
mysql_store_result() returned error 5 (out of memory (needed 48944 bytes)) allow mysqld to use more memory or you can add more swap space
服务器本身还有很多的内存,并未被占用,压测的时候CPU 并未在的状态下.
当时sysbench 来对MYSQL 8.011 版本的数据库进行压测,并发到达100,MYSQL就报OOM , 服务器的配置 4C 16G
基本上在配置上是没有太多的问题和可以被改正的点.
经过多次的折腾,我们想起之前在模板上修改了一个相关的参数vm.overcommit_memory=2 ,我们将 vm.overcommit_memory = 0 后问题消失,数据库压测1000- 3000个并发运行平稳.
问题解决了,但我们的说说怎么产生了这个问题,并且为什么更改了overcommit 问题就解决了.
overcommit 这个参数是存在在LINUX 系统上的参数,功能是操作系统给付给进程的内存的大小. 实际上内存永远不够用,一般都是通过虚拟和物理之间的映射.
先来看看相关的overcommit 的值和相关的解释,
其中值包含
0 1 2 三个值,
0 是缺省值, 运行overcommit ,在申请内存后会通过OS kernel 来进行判断你申请的内存是否合理,是否超分的太多.
1 一直运行overcommit 对内存的申请都能通过
2 允许进行内存的超分
故障的服务器的overcommit 设置的为2, 但内存并未使用完毕并且还剩余50%的情况下,MYSQL 频繁的DOWN 机,承受的连接数较低.
这里引入一个LINUX 发现内存不够使用后尽快KILL PROCESS的公式
CommitLimit = (Physical RAM * vm.overcommit_ratio / 100) + Swap
1 vm.overcommit_ratio 默认值是50%
这里以内存为16G 为例子, 16G * 0.5 + 5G =13G 也就是当内存分配超过13G 后, LINUX 系统会挑选出来大的PROCESS 来进行KILL .
这里选择了overcommit =2 也就是触发了当系统内存使用到 一半内存+SWAP的情况下,会导致 LINUX 将目前使用内存大的 MYSQLD的进程给KILL 了.
所以在未理解实际的vm.overcommit_ratio 的情况下修改了overcommit 认为修改后会使用大量的内存而不会一开始就使用SWAP的想法是错误的.
那么到底程序是怎么申请内存的,以MYSQL为例 正在运行的MYSQL 在申请内存时通过malloc()函数,来动态的分配内存,他找到与申请内存大小相同的未使用的连续的块,并且返回给MYSQL 相关的内存空间的指针. 而当系统没有内存的时候,malloc() 返回NULL 表明没有足够的内存,此时, 在linux系统中使用的是乐观类型的内存分配的方式, 系统希望并假定所有正在运行的应用程序都不会一次性的拿走自己要分配的内存, 当内存不足的情况下
1 将现有的内存暂不在使用的放入到磁盘进行交换,交换出空间
2 当将内存转移到磁盘通过磁盘模拟也无法HOLD 住内存的情况下,那么无法分配内存的程序就CRASH 了
LINUX 当发现这个问题就会根据系统的配置,以及底线,开始使用OOM Killer 来让一些他选择的应用程序终止工作.在LINUX 核心通过一个oom_badness() 的功能来进行工作.
那么那些应用程序容易被选择成 KILL的对象, 这里会通过内存的消耗, 到底这个进程的重要性,CPU 消耗, 等进行评估, 那么另一个问题是为什么他们要KILL MYSQL , 不能kILL别的程序吗?
实际上这个问题分析是可以写一篇的,这里限于时间和版面的问题,一句话表名就是MYSQL 如果是这个系统的内存大户,那他必然被KILL.
那么后如果有同学说我就是要设置overcommit_memory = 2 我不想用swap
OK ,
1 调整你的 overcommit_ratio 如 echo 99 > /proc/sys/vm/overcommit_ratio
2 不分配SWAP 给你的LINUX系统
但这样做真的好吗?