书接上一回:
自从上次对MySQL下狠手以后,我小破站的性能表现好了一些,但偶尔还是存在时好时坏的情况。
我还是有点纳闷的,你说要么一直不好就算了,还时好时坏的算怎么回事呢?
监测了一个多月的访问流量,发现和访问请求的关系也不大。所以还是认定是我服务器组件的问题。
然后我偶然发现,当服务器偶发响应缓慢的时候我只需要重启php-fpm,其它的组件比如MySQL等都不需要重启,网站的速度就能立即恢复。
难道php-fpm是罪魁祸首?
我网上找了找,有症状和我差不多的:
nginx php 过段时间 慢,Nginx+PHP-FPM时快时慢问题的解决-CSDN博客
该博主的排查结果,是linux内核的ulimit参数设置过小导致的。但我查了一下我的服务器,并没有这个问题。
但该博主的分析,倒是在另外一个地方启发了我:
我或许应该排查一下我的pm参数,特别是max_children,spare_servers等参数。
如何证明php-fpm是罪魁祸首?
既然想锁定php-fpm是问题根源,那就先看看它的运行日志。根据安装配置找到php-fpm.log位置,打开它。发现它里面的确经常会报:
WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning [x] children, there are [x] idle, and [x] total children
WARNING: [pool www] server reached pm.max_children setting ([x]), consider raising it
可以看到,日志已经清楚提醒我,我的php-fpm经常会出现server/children不够用的问题。是时候提高子线程数量了。
其实呢,一般而言这个设置不会这么快被碰到天花板的。可能是因为我采用了LNMP套装的缘故,LNMP默认地会把这些值设置得非常小,才会遇到我这个问题的。
这些值设置得小并不会造成服务器运行出错,但会造成运行缓慢。特别是当你在WordPress里面添加了越来越多的组件以后,常驻后台的或者并发运行的承载线程将会显著增多,便会越来越频繁地触碰到线程限制的天花板。然后php-fpm便会启动排队/强制注销的机制,于是从外面看起来,就是服务器和网站的运行偶发地变慢了。
LNMP把这些值默认地设置得小并非一无是处,在另一方面它会起到保护的作用。允许的并发过高可能会快速导致内存和CPU耗尽,而一般采用LNMP的主机配置都不会很高。所以这里可以看出LNMP作者的细心,提前为使用者考虑到了一些边界问题。
当然,我们可以根据自己的服务器配置,适当增加这些参数值,特别是我之前已经从内存消耗大户MySQL那里刨回来了不少内存占用的情况下。
如何解决?
首先,可以参考下方文章,它非常详尽地介绍了这些参数和背后的优化原理:
An Introduction to PHP-FPM Tuning – Tideways
然后打开我服务器上的php-fpm.conf文件。
首先看到的是,我的服务器采用的是dynamic的模式:
pm = dynamic
从这里我们也可以发现,前面CSDN的博主之所以没有这方面的问题,是因为他php-fpm采用的是static的静态模式,故不会有偶发快慢的问题。
而正因为我采用的是dynamic的动态模式,所以如何设定server/children的最大值最小值就很有必要。
研究日志发现,WordPress在配置了一定的插件以后,后台的php承载线程经常会在30个左右。
所以max_spare_servers最好大于40,确保WordPress的线程不会被过早强制释放:
pm.max_spare_servers = [某个大于40的数值]
然后,max_children比它大一些就可以了,当然你也可以设置到系统能力的最大值:
pm.max_children = [比max_spare_servers大一些的数值]
其它的参数,比如pm.start_servers和pm.min_spare_servers,就酌情设置就可以,可以参考上述链接的推荐值。
有一种说法是,start_servers是指每次php-fpm去fork的子线程数量,也就是新建线程数量的颗粒度,并非是单纯指初始启动时默认启动多少个子线程。如果此说法为真,那这个值不应该过大,否则也会导致运行缓慢,并且造成内存浪费。
还有一种说法是,这些值推荐是2的倍数,最好是CPU核心数的倍数,这样方便CPU处理。
如此设置过以后,我的服务器终于可以长时间运行也不再有时快时慢的问题了,运行日志里面前述的warning也不再出现过,从根本上解决了问题。