FastCGI:aborted:select()失败

时间:2014-02-06 04:37:12

标签: php apache fastcgi

我有运行Apache 2.2.4和PHP-FPM(FastCGI Process Manager)的VPS服务器(CentOS 6.5)。 每天2-3次我在error_log中遇到以下错误:

[error] [client 127.60.158.1] (4)Interrupted system call: FastCGI: comm with server "/usr/lib/cgi-bin/php5-fcgi" aborted: select() failed
[error] [client 127.60.158.1] FastCGI: incomplete headers (0 bytes) received from server "/usr/lib/cgi-bin/php5-fcgi"
[notice] caught SIGTERM, shutting down
[alert] (4)Interrupted system call: FastCGI: read() from pipe failed (0)
[alert] (4)Interrupted system call: FastCGI: the PM is shutting down, Apache seems to have disappeared - bye

因此,apache并不总是停止,有时只有主进程停止并且工作进程仍然运行,这使我甚至无法重启apache,因为它仍在侦听端口80,但没有主进程和pid文件。

我看到有人提到更新到mod_fastcgi 2.4.7(修补)修复了这个bug,但不幸的是RHEL / CentOS没有更新,所以这对我来说不是一个选项。 (Apache PHP5-FPM connection reset by peer

谷歌的回答还有线索,在fastcgi.conf中增加--idle-timeout的值可以解决问题,但我没有看到原因。

请问这个问题的解决方案吗?

1 个答案:

答案 0 :(得分:7)

增加-idle-timeout(前面只有一个破折号^^)确实是解决方案。对here给出了完整的解释,但我会尝试解释它:

PHP有自己的超时,在max_execution_time中设置。如果使用mod_php运行它,此设置将告诉PHP在x秒后退出脚本。

下一步:FPM流程管理器在池配置中设置了另一个request_terminate_timeout。这个限制/覆盖max_execution_time

这就是纯PHP方面的部分。如果您使用的是PHP-FPM和FastCGI,PHP将在其自己的进程中启动。内部超时仍然适用。然而,FastCGI有自己的超时(PHP不需要它,但fastCGI现在应该如何拥有自己的?),这可以确保网络服务器在某些CGI进程没有冻结时(或者只是工作了很长时间) )。

问题是:FastCGI只是杀死PHP和Apache之间的IO流,使PHP无法正常关闭。 FastCGI已经收到的数据仍然移交给Apache - 如果它不完整,它会引发错误(你看到的关于不完整标题的错误)。除此之外,PHP进程保持在那里,在僵尸状态下运行,无法使用,因为IO流现在已经死了。您可能必须手动终止它们或等到PHP-FPM希望这样做(取决于进程管理器设置)。你得到的其他错误是由PHP生成的,原因如下:管道已关闭,Apache在另一端“消失”。

所以:确保FastCGIs超时比request_terminate_timeout更高(至少一秒),并且这个超过你在max_execution_time中使用的最高值至少另一秒。

请注意,后者可以使用ini_set进行更改,因此请务必记住哪些值有效,哪些值无效 - 或者在FPM池配置中使用php_admin_value进行设置,因此不能在个别脚本中更改(请参阅documentation)。不是因为它是必要的(只要它低于FastCGI超时,request_terminate_timeout将正确终止PHP子进程),但是因为如果设置max_execution_time失败,你的脚本可以正确检测到超时,而他们会认为它是有效的如果他们可以覆盖它(没有办法从PHP脚本中读取request_terminate_timeout)。

您可以分别更改每个池的所有值:

  • max_execution_time通过泳池配置中的php_value / php_admin_value

  • request_terminate_timeout直接在泳池配置

  • Apache配置中的FastCGIs -idle-timeout,其中每个池都必须单独添加:

    FastCgiExternalServer /usr/lib/cgi-bin/external.php5.www -socket /var/run/php5-fpm/www.sock -pass-header Authorization -idle-timeout 310 -flush

    (路径当然可能不同,这只是我的配置引用,但我建议使用Authorization的pass-header,虽然与此问题无关。)