Apache, PHP Fastcgi and PHP_FCGI_CHILDREN

Tagged:  

We had long suspected that something wasn't quite acting as advertised with our PHP Fastcgi set up. Not that we had any issues, but like many tutorials recommend, we using a wrapper script to run the fastcgi enabled version of php. In that wrapper script we set PHP_FCGI_CHILDREN variable and exec'd php. Here is the snippet from our config:

Apache:

ScriptAlias /php-fastcgi/ /path/to/users/home/php-fastcgi/
AddType application/x-httpd-fastphp .php
Action application/x-httpd-fastphp /php-fastcgi/php5-fcgi

php5-fcgi:

#!/bin/sh
PHPRC="/etc/php4/cgi"
export PHPRC
PHP_FCGI_CHILDREN=4
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_MAX_REQUESTS
exec /usr/lib/cgi-bin/php4

So for every site, an instance of php would be launched to talk to apache via factcgi and that php instance would, in turn, launch 4 children processes to actually handle the requests, giving 5 processes in total.

Now there were a couple of things with this set up. The first, which was a minor headache, was that often an apache reload would kill the instance of php it was talking to, but the 4 children would be left behind. This was annoying, but would only take up a bit of memory and we wrote a script to clean them up.

The other thing with this set up is that it didn't seem to make any difference to the sites what PHP_FCGI_CHILDREN was set to. It turns out there was a reason for this. After receiving several alerts for the number of processes on our web servers, we thought we'd find out what was going on.

This thread was very informative on the topic:
http://www.mail-archive.com/mod-fcgid-users@lists.sourceforge.net/msg002....

Apache with fcgid will launch one fastcgi child (in this case php5-fcgi) for each request that needs to be serviced. This means that if apache receives 2 concurrent php requests for the same site, 2 php fastcgi processes will be launched, with each in turn launching 4 children. This means that only one of the php children will ever be used (which we verified using strace). So, since the php processes are being managed by mod_fcgid, there is no point in also configuring php to manage processes. PHP_FCGI_CHILDREN is only useful when the php instance is a stand alone fcgi server as in nginx or lighttpd.

To confirm this behaviour, we reloaded apache and confirmed that there were no php processes running for the test site. We then ran the following script:

#!/bin/sh
wget http://testsite/test.php -q &
wget http://testsite/test.php -q &
wget http://testsite/test.php -q &
wget http://testsite/test.php -q &
wget http://testsite/test.php -q &
wait

Where test.php is the following:

<?php
sleep(5);
echo 'OK';
?>

So the code will produce 5 concurrent requests. Running this resulted in 25 php5-fcgi processes, which means 5 copies of the script were launched each with 5 processes (1 talking to mod_fcgid and 4 children). So it appears that setting PHP_FCGI_CHILDREN is pointless under mod_fcgi/apache as each group will only ever handle 1 request at a time. We have therefore removed the PHP_FCGI_CHILDREN value from our php5-fcgi scripts to give the following:

#!/bin/sh
PHPRC="/etc/php4/cgi"
export PHPRC
PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_MAX_REQUESTS
exec /usr/lib/cgi-bin/php4

This has had no adverse consequences and we now have about a fifth of the processes running on the web servers and no problems with lost children.

The apache documentation for fcgid clear states the following

"PHP child process management (PHP_FCGI_CHILDREN) should always be disabled with mod_fcgid, which will only route one request at a time to application processes it has spawned; thus, any child processes created by PHP will not be used effectively. (Additionally, the PHP child processes may not be terminated properly.) By default, and with the environment variable setting PHP_FCGI_CHILDREN=0, PHP child process management is disabled."

Read more at: http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html#fcgidmaxprocesses

Thanks for the reference. This post was written before mod_fcgid was a part of apache and had such complete docs. Looks like things have improved!

Thanks. This has helped me understand why I had a ton of stagnant PHP processes from way back in April!!!

So in the end how is it possible to limit the number of spawned processes.

In this case, you would have to limit the number of Apache children.

Using mod_fastcgi instead of mod_fcgi?
While mod_fcgid only sends one request per child process, mod_fastcgi sends multiple simultaneous requests to a single PHP process if the PHP process has children that can handle it.

(See: http://www.brandonturner.net/blog/2009/07/fastcgi_with_php_opcode_cache/).

Cheers,
Nikolas

You should set PHP_FCGI_CHILDREN=0 if you are using a dynamic configuration via FastCgiConfig. Only set PHP_FCGI_CHILDREN=4 or other non-zero value if you have specified a static fastcgi server using FastCgiServer.

If you are using a dynamic configuration _and_ a non-zero value, then Apache and php-cgi will both try to manage the number of php-cgi processes and you will get too many.

I agree! My issue is that there as lots (and I mean *lots*) of tutorials out there recommending PHP_FCGI_CHILDREN=4 or similar with an apache setup!