从children进程数优化php网站

故障描述

不少使用wordpress的用户会遇到“Error establishing a database connection”的问题,我从建站不久到几个小时前的这段时间都被这个问题困扰着,总是会时不时的报出无法链接到服务器之类的错误。查看进程状态都会显示mysql挂掉了,而且腾讯云的服务器内存监控图是呈“几”字形的大起大落。

问题查找

来看看问题出在哪里,使用cat cat /var/log/mysqld.log来查看mysql究竟经历了什么,找到了如下语句:

InnoDB: mmap(137363456 bytes) failed; errno 12
2017-06-22 21:16:43 24489 [ERROR] InnoDB: Cannot allocate memory for the buffer pool
2017-06-22 21:16:43 24489 [ERROR] Plugin ‘InnoDB’ init function returned error.
2017-06-22 21:16:43 24489 [ERROR] Plugin ‘InnoDB’ registration as a STORAGE ENGINE failed.
2017-06-22 21:16:43 24489 [ERROR] Unknown/unsupported storage engine: InnoDB
2017-06-22 21:16:43 24489 [ERROR] Aborting

果然就是内存不足导致mysql崩溃。
仔细想想,服务器上最吃内存的除了mysql就是php了。

不少站长都知道,php会创建一些子进程,(应该是对于每个会话对应一个子进程,呃,没有深入研究过php,不是很肯定)使用top命令就可查到
在命令行输入$ top,再按Shift+m进行按占用内存进行排序
top

由于Mysql中占用绝大多数内存的是它的缓冲区(查询啊,写入啊都是在缓冲区里进行的),波动一般不超过1%,绝不是Mysql把自己爆掉了。除了mysql,最占内存的就是php了,别看一个php子进程占用那么少,加起来就多了。

使用命令ps -fe |grep "php-fpm"|grep "pool"|wc -l 看看一共有多少个php子进程
显示了31个!(小站应该不会有人来攻击我吧,怀疑是搜索引擎的爬虫造成)
当时数据库崩溃后大概一个进程占2.2%左右吧,崩溃时可能更高,31*2.2%=68.2,加上系统和nginx等软件运行所需,mysql不崩溃才怪嘞,尤其是InnoDB这样特别吃内存的引擎。(我的服务器内存是1G的,一般每个php子进程在启动一段时间后,占用20~30M,的确顶不住三十多个)

现在来算一算,Mysql占用47%,除去系统和其他软件,分配40%给php就可以了,而且不是每个子进程都能跑到30M,为了使空闲子进程不过分的占用内存,就把它空闲子进程限制在16个以内吧。

php默认的进程池是www,不确定的话可以通过$ ps -ef | grep php-fpm查看进程池:

root 3028 1 0 20:33 ? 00:00:00 php-fpm: master process (/usr/local/php/etc/php-fpm.conf)
nobody 3029 3028 0 20:33 ? 00:00:00 php-fpm: pool www
nobody 3030 3028 0 20:33 ? 00:00:00 php-fpm: pool www

使用命令$ vi /etc/php-fpm.d/www.conf修改进程池配置文件,一般在文件中都会设定了对于的值,改掉即可,找不到再进行添加(另外记得养成修改配置文件前复制一份,重命名备份的习惯,说多了都是泪

# pm = static 为静态分配进程池,固定大小,8G及以上的大内存主机设置最佳
# pm.max_children=100 静态方式下开启的php-fpm进程数量

# dynamic为动态分配,会结束掉多余的进程,可以回收释放一些内存,所以我选择了动态
pm = dynamic

# php-fpm启动时的初始子进程数量
pm.start_servers = 5

# 处于空闲"idle"状态的最小子进程,如果空闲进程数量小于这个值,那么相应的子进程会被创建
pm.min_spare_servers = 5

# 最大空闲子进程数量,空闲子进程数量超过这个值,那么相应的子进程会被杀掉。
pm.max_spare_servers = 16

修改完成后保存退出。
systemctl restart php-fpm重启php使配置生效。

现在内存总占用稳定在800M之下,不再发生“因php子进程过多导致内存不足,而引发mysql崩溃”的这种情况了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注