实践统计php-fpm负载情况
最近想对线上机器web负载情况做一次调查,线上环境是nginx+php-fpm的搭配,我们知道一次http请求的流程是
①客户端发起请求到80等端口;
②服务端nginx主进程监控80端口,对任务进行分发给worker进程;
③nginx的worker进程根据配置将请求转发给fcgi,这里环境是9000端口的php-fpm;
④监控9000端口的php-fpm主进程根据配置将请求静态(或动态)交给php-fpm子进程处理;
⑤php-fpm子进程处理完毕原路返回数据报。
于是乎,我们统计fpm负载情况也就有方案了:根据端口监听情况来统计。统计代码也很简单:
1 2 3 | netstat -anpt | grep 'php' | awk -F ' ' '{print $7}' | awk -F '/' '{print $1}' | sort | uniq | wc -l //注:我这里把端口监听进程的进程名也打出来,可以看到php>5.3的进程名是php-fpm,php<5.3抓出来的是php-cgi //这里还有个细节,因为抓的关键字是php,所以对抓出来的进程号进行率重,抓端口监听号会便捷些 |
下面描述我的实践过程:
一,了解php-fpm配置参数
fpm可支持多进程池,不同进程池的配置可以分别配置,下图为实例。
1 2 3 4 5 6 7 8 9 10 | listen = 127.0.0.1:9000//fpm监听端口,即nginx中php处理的地址,一般默认值即可。 listen.allowed_clients = 127.0.0.1//允许访问FastCGI进程的IP,设置any为不限制IP,如果要设置其他主机的nginx也能访问这台FPM进程,listen处要设置成本地可被访问的IP。默认值是any。每个地址是用逗号分隔. 如果没有设置或者为空,则允许任何服务器请求连接. user = www//启动进程的用户 group = www//启动进程的组 <span style="color: #ff0000;"><strong>pm = dynamic</strong></span>//如何控制子进程,选项有static和dynamic。如果选择static,则由pm.max_children指定固定的子进程数;如果选择dynamic,则由下开参数决定。对于专用服务器,pm可以设置为static。 pm.max_children = 5//子进程最大数 pm.start_servers = 3 //启动时的进程数 pm.min_spare_servers = 3 //保证空闲进程数最小值,如果空闲进程小于此值,则创建新的子进程 pm.max_spare_servers = 3 //保证空闲进程数最大值,如果空闲进程大于此值,此进行清理 pm.max_requests = 1000//设置每个子进程重生之前服务的请求数. 对于可能存在内存泄漏的第三方模块来说是非常有用的. 如果设置为 '0′ 则一直接受请求. 等同于 PHP_FCGI_MAX_REQUESTS 环境变量. 默认值: 0. |
这里pm的值设置会对php产生比较大的影响,如果设置为static,则php-fpm启动后会生成多个常驻子进程进行等待,若为dynamic则会根据fpm的优化策略来控制子进程数,这两种方案各有好处,如果是专门的web服务可以选用static,这样可以减少开辟进程带来的cpu开销。
注意:这里由于php版本不同,所以看到的进程名是不同的。
二,验证dynamic形式与进程监听状态
了解了fpm的工作机制后,下面我们来验证猜想。采用的方案是利用压测工具http_load和监控工具watch来观察变化。压测前的状态:
进程状态如图一。
这里用到的两条命令:
1 2 | //压测机命令 http_load -rate 10 -seconds 10 url.txt //url.txt为一个url:http://iamjs.net/lbb.php |
1 2 3 | //监控机命令 watch -n 0.5 'netstat -anpt | grep php-fpm' watch -n 1 'ps aux | grep php | grep -v grep' |
上面例子用的是按每分钟10次的频率进行10s的压测,结果如下图:
由此可以验证我们的猜想。
三,结论
实际上我们可以写个脚本定时监控php进程的端口监听数,如果长期和fpm设置的定值(或最大值)一样,并且nginx经常出现502的错误,就要考虑调高fpm控制的进程数了。
学习nginx工作原理 计算TCP、nginx、mysql连接数