Apache2 + mod_fcgid + PHP = Awesome
For years now I was using PHP as a Apache module and not thinking twice about it. Easy to install not much to maintain and working reasonably well. Server too slow? Buy a new server. Recently one of our servers got really slow again with varying timeouts while serving pages. Memory shortage. No new server available I needed to make the most of it and started investigating how to decrease the memory footprint of Apache.
FastCGI was the answer. With PHP as a module installed every Apache process can take up to the maximum amount of memory you defined in php.ini plus what the Apache process needs by himself even though this process is only serving static content. With the switch to FastCGI it was possible to use the threaded version of Apache (mpm_worker). Static contents are now served really fast without need for invoking PHP at all. PHP scripts are served by calling the FastCGI IPC.
As memory is still low Apache and PHP are both configured to “die” after quite a low number of requests served. This can sometimes lead to a small delay while the processes are restarted but ensures that the memory footprint is kept low.
How did I do it? I won’t go into details on how to install Apache, mod_fcgid and PHP because there are loads of howto’s out there. Please find the configuration I’m using below. I’m using Debian and Apache, mod_fcgid and PHP are installed out of the repository. If you have a custom compiled version or different distribution your paths can differ.
Depending on your available hardware it is feasible to tweak the settings for the mpm_worker module so more concurrent clients can be served and/or the amount of requests which is handled before re-creating the thread is higher. It is also very recommended to use eAccelerator in conjunction with this setup. See my post on the topic for more information.
/etc/apache2/apache2.conf (excerpt):
<IfModule mpm_worker_module> StartServers 4 ServerLimit 4 MaxClients 128 MinSpareThreads 8 MaxSpareThreads 16 ThreadsPerChild 32 MaxRequestsPerChild 500 </IfModule>
/etc/apache2/mods-available/fcgid.conf:
<IfModule mod_fcgid.c> AddHandler fcgid-script .fcgi .php FCGIWrapper /var/www/php-fcgi-starter .php IdleTimeout 3600 BusyTimeout 300 ProcessLifeTime 7200 IPCConnectTimeout 10 IPCCommTimeout 360 MaxProcessCount 15 MaxRequestsPerProcess -1 PHP_Fix_Pathinfo_Enable 1 </IfModule>
/var/www/php-fcgi-starter:
#!/bin/sh PHPRC=/etc/php5/cgi/ export PHPRC export PHP_FCGI_MAX_REQUESTS=250 export PHP_FCGI_CHILDREN=1 exec /usr/lib/cgi-bin/php