php日志中有一个超时日志,但是我的request_terminate_timeout设置为0,所以理论上应该没有超时。
PHP致命错误:中超过了30秒的最大执行时间.
好的,首先列出当前配置:
PHP-fpm : request _ terminate _ time out=0 PHP . ini : max _ execution _ time=30
首先,我检查了php-fpm文件中关于request_terminate_timeout的注释
;为单个请求提供服务的超时,超过该超时后,工作进程将;被杀死。当使用“max _ execution _ time”ini选项时,应使用此选项;不会因为某种原因停止脚本执行。值“0”表示“关”。可用单位: s(秒)(默认)、m(分钟)、h(我们的)或d(天);默认值: 0
该注释显示,当max_execution_time由于某种原因无法终止脚本时,request_terminate_timeout适用于终止这个php-fpm请求。
再看max_execution_time的注释:这设置了解析器中止脚本之前允许的最大执行时间,默认为30s。看来我的请求应该是被设置max_execution_time扼杀了。
好了,不要放弃,做个实验:
设置php-fpm request _ terminate _ time out 0 15 PHP . inimax _ execution _ time设置30 30执行结果PHP有致命错误超时日志,http状态码为500 php没有致命错误超时日志,http状态码为502,php-fpm日志中有一个杀死子进程的日志。结论是web请求的php执行时间是由两个方面控制的,一个是php.ini的max_execution_time(注意睡眠,等待http请求响应的时间不计算在内,但这里计算的是真正的执行时间),另一个是PHP-fpmrequest _ terminate _ time out设置,从请求开始算起n秒。
请求终止超时导致的资源问题
如果request_terminate_timeout的值设置为0或太长,可能会导致file_get_contents的资源问题。如果file_get_contents请求的远程资源反应太慢,file_get_contents将一直停留在那里而不会超时。我们知道php.ini中的max_execution_time可以设置php脚本的最大执行时间,但是这个参数在php-cgi(php-fpm)中不会生效。
php-fpm.conf配置文件中的request_terminate_timeout参数可以真正控制php脚本的最大执行时间。request_terminate_timeout的默认值为0秒,这意味着PHP脚本将始终被执行。因此,当所有的php-cgi进程都卡在file_get_contents()函数中时,这个Nginx php WebServer就不能再处理新的PHP请求了。
Nginx将向用户返回“502坏网关”。需要修改这个参数,设置一个PHP脚本的最大执行时间,但是症状并不是根本原因。比如改成30s,如果file_get_contents()获取网页内容比较慢,就意味着150个php-cgi进程每秒只能处理5个请求,WebServer也很难避免“502 Bad Gateway”。
解决方法是:将request_terminate_timeout设置为10s或一个合理的值,或者为file_get_contents添加一个超时参数。
$ CTX=stream _ context _ create(array(' http '=array(' time out '=10//以秒为单位设置超时));file_get_contents($str,0,$ CTX);最好不要在php-fpm中设置request_terminate_timeout
就在我转到php-fpm的几天后,我发现当我进入joomla后台时,firefox偶尔会给我那种白屏的http 503。这种情况只出现在天翼云的服务器上,而我国外同样配置的服务器完全没有问题。后来发现是request_terminate_timeout的问题。
每次登录joomla后台,joomla都会检查是否有更新(检查成功后,缓存默认保存6小时),分为joomla主程序和joomla扩展,如下图所示:
毫不奇怪,服务器将启动两个php进程,这两个进程被分配给两个php-fpm子进程来连接joomla的官方更新服务器。好了,问题来了。我的请求_终止_超时=30s。如果30s内没有完成,将超时。看天翼云主机的国际退出。好痛!没错,30秒内,天翼云主机无法完成连接joomla更新服务器并检查是否有更新的整个过程。这也解释了为什么同样配置的国外服务器没有问题,因为它们只需要2~5秒左右就可以完成上面的详细过程。
我的apache超时设置是30秒,php.ini中最长的执行时间是30秒。已经很多年没有问题了,没有30秒打不开的网页,所以给PHP-fpm request _ terminate _ time out=30s也没多想。经过这次事件,我发现这30秒并不是卑鄙的30秒.
php.ini中的Max_execution_time和max_input_time在php-fpm设置request_terminate_timeout后无效,以php-fpm中的设置为准。Apache mod_php只会在超时后记录在日志中,仅此而已。在php-fpm中的request_terminate_timeout超时后,http 503被记录在日志中,它将直接杀死导致这个http 503的php-fpm子代,并生成一个新的子代。在我的joomla更新示例中,两个php-fpm孩子将同时被杀死。而且我的天翼云主机比较低调,只有一个cpu核心,我只启动了两个php-fpm的孩子,两个都是同时死的,所以我的火狐端有一个http 503 Service Unavailable的白屏。php-fpm的Error_log如下:
[2014年9月27日10:41:06]警告: [pool www] child 1882,script '/home/onepx/public _ html/administrator/index . PHP '(request : ' POST/administrator/index . PHP ')执行超时(30.004534秒),终止[2014年9月27日10:413:06]警告:06
[27-Sep-2014 10:41:06]NOTICE :[pool www]child 1886开始[27-Sep-2014 10:41:06]WARN :[pool www]child 1883,script '/home/onepx/public _ html/administrator/index . PHP '(request : ' POST/administrator/index . PHP ')执行超时
像joomla这样的php网站的每一个连接都需要apache php-fpm一起工作。即使php-fpm中的request_terminate_timeout设置很长,而apache中的timeout设置略短,只要apache超时,php-fpm仍然会在后面终止进程.如果网站访客很多,php-fpm的子节点被很多访客共享,杀死一个子节点可能会导致多个用户同时使http 503 Service不可用。所以我的建议是不要设置—— HP-fpm中的request_terminate_timeout,只给apache一个超时。