后篇,服务器负载过高

虽然昨天通过引流的方式,将频繁的价格请求转发到了一台被集群踢掉的机器。可是眼看着那台机器负载一直保持在100+,还真担心那机器的CPU爆掉呢。于是今天继续对这个问题展开了研究,好在研究有了结果。

首先用CPU火焰图绘出CPU的具体调用


这里就看的很明显了,php-fpm栈里面有一个getdents64尤其的亮眼。那么这个getdents64又是何物呢?这里祭出Linux man page的解释

The system call getdents() reads several linux-dirent structures from the directory referred to by the open file descriptor fd into the buffer pointed to by dirp. The argument count specifies the size of that buffer.

可是PHP程序为何会有这么多的对文件的操作呢。现在服务器只处理这个价格的请求,而且运行的这么慢,php-fpm的slowlog里应该有些记录吧,去碰碰运气。

script_filename = xxx/metals/index.php
[0x0000000001f98088] read() xxx/include/cache.php:35
[0x0000000001f97b48] delete() xxx/include/cache.php:50
[0x0000000001f97280] check() xxx/metals/index.php:30

果然slowlog没有让我失望,记录了大量如上的日志。赶紧去文件里所标示的那几行看看代码压压惊,发现这里一直要去缓存目录。于是去缓存目录一探究竟,发现ll执行一下都非常的慢,原来这个文件夹里已经有好几万的文件了,程序到这里来自然非常的慢,也就不难解释火焰图表现的情况了。

想起来前几天程序里更新了缓存文件的生成机制,又不对老旧的缓存文件做删除,导致文件的累计。所以解决方法自然就是在系统的tmpfs分区新建缓存目录,修改程序配置文件应用新的缓存目录。此时负载立刻下降,但是新缓存目录里并没有生成文件。看样子更新价格的请求只是去缓存目录遍历文件,并不做写入,所以IO一直没有过高,跟我以前遇到的服务器过载的情况也就不一样了。最后设置crontab每天凌晨清空缓存目录,防止新缓存目录出现同样的问题。