-->

FastCGI: aborted: select() failed

2020-07-24 11:49发布

问题:

I have VPS server (CentOS 6.5) running Apache 2.2.4 and PHP-FPM (FastCGI Process Manager). 2-3 times a day I get following errors in 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

And as a result apache not always stops, sometimes only main process stops and worker processes still run which prevents me even to restart apache as it's still listening on port 80, but without main process and pid file.

I saw somebody mention to update to mod_fastcgi 2.4.7 (patched) which fixes that bug, but unfortunately RHEL/CentOS doesn't have that updates, so that is not an option for me. (Apache PHP5-FPM connection reset by peer)

Also there was thread on google answers that increasing value of --idle-timeout in fastcgi.conf can solve the issue, but I don't see the reason.

Any solutions for this problem, please?

回答1:

Increasing -idle-timeout (just one dash in front though ^^) is indeed the solution. A complete explanation on this is given here, but I'll try to explain it:

PHP has it's own timeout, set in max_execution_time. If running it using mod_php, this setting tells PHP to quit working on a script after x seconds.

Next: the FPM process manager has another one, request_terminate_timeoutset in the pool configuration. This one limits / overrides max_execution_time.

That's it for the pure PHP-side part. If you're using PHP-FPM and FastCGI, PHP is started in its own process. The internal timeouts still apply. FastCGI however has its own timeout (which isn't needed for PHP, but how should fastCGI now PHP has its own?), that makes sure the webserver doesn't freeze if some CGI process does (or just works for a very long time).

The problem is: FastCGI just kills the IO stream between PHP and Apache, giving PHP no chance to properly shut down. Data that has already been received by FastCGI is still handed over to Apache - if it's incomplete, it'll raise an error (the one you see about incomplete headers). In addition to that, the PHP processes stay there, running in a zombie-like state, unusable because there IO stream is now dead. You may have to kill them manually or wait until PHP-FPM hopefully does (depending on process manager settings). The other errors you're getting are generated by PHP for this exact reason: Pipe was closed, Apache "disappeared" on the other end.

So: Make sure FastCGIs timeout is higher (by at least one second) than request_terminate_timeout, and this one is higher by at least another second than the highest value you use in max_execution_time.

Note that the latter can be changed using ini_set, so make sure to remember what values do work and what don't - or set it using php_admin_value in your FPM pool configuration, so it cannot be changed inside individual scripts (see the documentation). Not because it's necessary (request_terminate_timeout will terminate PHP children properly as long as it'S lower than the FastCGI timeout), but because your scripts can detect the timeout properly if setting max_execution_time fails, while they will asusme it worked if they can override it (there is no way to read request_terminate_timeout from inside PHP scripts).

You can change all values for each pool separately:

  • max_execution_time via php_value/php_admin_value inside the pool config

  • request_terminate_timeout directly inside the pool config

  • FastCGIs -idle-timeout in the Apache config, where each pool has to be added separately anyway:

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

    (paths may be different of course, this is just a quote from my config, but I'd recommend the pass-header for Authorization, although not related to this problem).