服务器莫名的内存高占用 导致 MySQL 停止运行问题
这问题是年后开始出现的,服务器内存占用越来越高,一度达到90%,最后 MySQL 都停止运行了。贴吧签到的数据库用户 ID 这一项也丢失了,导致无法签到,断签了好些天,被提醒才发现,要挨打的。幸好设置了自动备份,把数据恢复,然后提高了签到频率,没想到后边反复出现了几次,不得不重视。
出现了几次就不是偶然了,最后每次都飙到85%,只能重启服务器解决。第一次出现时以为是 MySQL 数据库的自身问题,可能因服务器内存小而崩溃,实际1.8G 的运行内存不大不小的。查了数据库日志发现数据库因分配内存不足而启动失败,用 top 命令也查了下,内存高占用的前 20 有 MySQL,是个大头,于是添加了 2G 的 Swap 虚拟内存,再添加了数据库进程守护,计划任务每5分钟运行一次,检测到 MySQL 不运行了就重新启动。
pgrep -x mysqld &> /dev/null
if [ $? -ne 0 ];then
bash /www/server/panel/script/rememory.sh
/etc/init.d/mysqld start
fi
结果过了些天问题依旧出现了,4G 内存也不够耗。这就有点莫名其妙的,之前一直运行好几年稳如狗的,怎么突然就这样呢?回想一下自己的操作,除了升级高版本宝塔面板好像就没了,升个大版本应该不会突然占用飙升吧,查进程看面板占用也才几十 MB ,到论坛也没见有人反馈,说明不是这个原因。
最后用 ps 命令仔细查看了所有进程,终于发现了问题的源头,是贴吧签到的定时任务和 php-fpm 。如果需要不间断地自动签到,那就得不停地访问执行签到的 do.php 页面。进程中发现了几十个正在运行的 do.php 和php-fpm 进程。
原来设置的是一分钟执行一次的 crontab ,后来似乎是嫌签到太慢,我就就按着查到的方法改为 10 秒执行签到一次:
php /www/wwwroot/qiandao/do.php
sleep 10;
php /www/wwwroot/qiandao/do.php
sleep 20;
php /www/wwwroot/qiandao/do.php
sleep 30;
php /www/wwwroot/qiandao/do.php
sleep 40;
php /www/wwwroot/qiandao/do.php
sleep 50;
php /www/wwwroot/qiandao/do.php
面板提供的计划任务功能最小只能 N 分钟执行,就查了下,了解到可以用 sleep 来实现。虽然知道在 C++ 程序中长时间延迟不能用 sleep ,都是用不会导致程序假死阻塞的定时器,但在这计划任务中PHP用应该没问题吧?还是 to young to simple 了,去除 sleep ,改回一分钟执行一次,重启服务器,再也没出现内存爆满的问题了,回到了以前正常占用内存60%左右。
最开始只用了 top 查内存高占用的前 20 进程,所以没发现是 do.php 和 php-fpm 的原因。一个进程只占了不到 9 mb ,虽然PHP管理中限制了 php-fpm 最大子进程数是50个,但到50个后,do.php 进程也达到 50 ,两个加起来占用就飙到 900 MB 了,妥妥地爆满。
正常我的网站 PHP 需求 是不会产生几十个进程的,是使用 sleep 导致了这个问题。原因大概是采用 FPM 管理 PHP 进程,由于 sleep 导致阻塞等待,FPM 实际分配了过多子进程,然后我的 PHP 并发方案是设置的 2G ,问题就这么产生了。