Introduction

PHP en couplage avec un serveur Web, les différents moyens de communication, leurs avantages et inconvénients :

Si vous cherchez la performance, rien ne remplace encore aujourd'hui un module de serveur Web : fusionner PHP dans le serveur Web est le meilleur moyen d'obtenir des performances élevées car il n'y a aucune communication inter-processus à gérer par le noyau, tout est encapsulé dans un seul processus, celui du serveur Web.

En revanche cette solution demeure très difficile à sécuriser si l'on veut héberger plusieurs sites sur une même instance de serveur. Ce n'est pas le cas de tout le monde, si vous n'avez pas de problématique de partage de PHP entre plusieurs sites Web différents, utilisez clairement la SAPI module.

Le module de serveur donne les meilleures performances, après entre FastCGI+SuEXEC et FPM, c'est à peu près équivalent même si FPM semble légèrement l'emporter. CGI reste lui, tout en bas du classement avec les performances les moins bonnes.

Fast CGI

  • FastCGI est une technique permettant la communication entre un serveur HTTP et un logiciel indépendant.

Par exemple sur Apache 2.x on peut utiliser le module mod_fcgid.

Et utiliser sa documentation : Apache Module mod_fcgid

PS : Notez qu'il s'agit de la documentation Apache HTTP Server Version 2.3, et que le nom des attributs des variables du mod FastCGI a changé !

Erreurs rencontrés

500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator, webmaster@placeoweb.com and inform them of the time the error occurred, and anything you might have done that may have caused the error.

More information about this error may be available in the server error log.

Internal Server Error The server encountered an internal error or misconfiguration and was unable to complete your request. Please contact the server administrator, webmaster@placeoweb.com and inform them of the time the error occurred, and anything you might have done that may have caused the error. More information about this error may be available in the server error log.

Voir le l'ancien beug : Bug #41593 FastCGI does not handle graceful reload/shutdown

Petit programme de test, pour éviter les erreurs
<?php
  	$timetosleep = isset($_REQUEST['time'])?$_REQUEST['time']:30;
 
 	$a = time();
	sleep($timetosleep);
 
	echo time()-$a;
 
	echo "Done with $timetosleep";
?>
Configuration brutale qui semble stable :
<VirtualHost *:80>
 
        <IfModule mod_fcgid.c>
                SuexecUserGroup userweb1 users
                PHP_Fix_Pathinfo_Enable 1
                <Directory /var/www/userweb1 />
                        Options +ExecCGI
                        AllowOverride All
                        AddHandler fcgid-script .php
                        FCGIWrapper /var/www/php-fcgi-scripts/userweb1 /php-fcgi-starter .php
                        Order allow,deny
                        Allow from all
                </Directory>
 
# http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html
 
# IdleScanInterval      FcgidIdleScanInterval   Default:        FcgidIdleScanInterval 120
IdleScanInterval 600
# IdleTimeout   FcgidIdleTimeout                                Default:        FcgidIdleTimeout 300
IdleTimeout 600
# IPCCommTimeout        FcgidIOTimeout                          Default:        FcgidIOTimeout 40
IPCCommTimeout 600
# IPCConnectTimeout     FcgidConnectTimeout             Default:        FcgidConnectTimeout 3
IPCConnectTimeout 300
 
        </IfModule>
 
</VirtualHost>

Ressources

   # Communication timeout: Default value is 20 seconds
   IPCCommTimeout 60
   
   # Connection timeout: Default value is 3 seconds
   
   #IPCConnectTimeout 3

   # Number of PHP childs that will be launched. Leave undefined to let PHP decide.
   #DefaultInitEnv PHP_FCGI_CHILDREN 3
   
   # Maximum requests before a process is stopped and a new one is launched
   #DefaultInitEnv PHP_FCGI_MAX_REQUESTS 5000
PHP_FCGI_CHILDREN

PHP terminera un processus fils lorsque le nombre de requêtes spécifié par PHP_FCGI_MAX_REQUESTS a été atteint.

La variable d'environnement PHP_FCGI_CHILDREN contrôle le nombre de fils que PHP appelle pour gérer les demandes. La variable d'environnement PHP_FCGI_MAX_REQUESTS détermine la durée de vie, en nombre de requêtes, de chaque fils.

SAPI : FastCGI Process Manager
# Short-Description: starts php5-fpm
# Description:       starts the PHP FastCGI Process Manager daemon
SERVEUR_WEB_PHP:~# /etc/init.d/php5-fpm restart
Gracefully shutting down php5-fpm warning, no pid file found - php5-fpm is not running ?
Starting php5-fpm Jul 29 10:05:14.336182 [ALERT] [pool www] pm.min_spare_servers(0) must be a positive value
Jul 29 10:05:14.336373 [ERROR] failed to post process the configuration

Solution sur dotdeb

There should be a default for pm.min_spare_servers / pm.max_spare_servers (5 and 35 is used in comments in the default ini).
This default can be provided in the default ini (just uncomment the lines), or hardcoded in php-fpm itself.
Otherwise, the ini won’t work out of the box, resulting in errors like:
This prevents:
[ALERT] [pool www] pm.min_spare_servers(0) must be a positive value
[ERROR] failed to post process the configuration
SERVEUR_WEB_PHP:/etc/php5/fpm# /etc/init.d/php5-fpm restart
Gracefully shutting down php5-fpm warning, no pid file found - php5-fpm is not running ?
Starting php5-fpm Jul 29 10:13:41.791364 [WARNING] [pool www] pm.start_servers is not set. It's been set to 20.
................................... failed
SERVEUR_WEB_PHP:/etc/php5/fpm# ps faux
root      2725  0.0  0.2 174828  5252 ?        Ss   10:13   0:00 /usr/bin/php5-fpm --fpm-config /etc/php5/fpm/php5-fpm.conf
www-data  2726  0.0  0.2 174824  4628 ?        S    10:13   0:00  \_ /usr/bin/php5-fpm --fpm-config /etc/php5/fpm/php5-fpm.conf
www-data  2727  0.0  0.2 174824  4628 ?        S    10:13   0:00  \_ /usr/bin/php5-fpm --fpm-config /etc/php5/fpm/php5-fpm.conf
www-data  2728  0.0  0.2 174824  4628 ?        S    10:13   0:00  \_ /usr/bin/php5-fpm --fpm-config /etc/php5/fpm/php5-fpm.conf
www-data  2729  0.0  0.2 174824  4628 ?        S    10:13   0:00  \_ /usr/bin/php5-fpm --fpm-config /etc/php5/fpm/php5-fpm.conf
PHP 5.2.13, 5.2.14 et PHP 5.3.2, 5.3.3 README.FastCGI (php-5.3.3\sapi\cgi\README.FastCGI) : SAPI : CGI / FastCGI
There are a few tuning parameters that can be tweaked to control the
performance of FastCGI PHP. The following are environment variables that can
be set before running the PHP binary:

PHP_FCGI_CHILDREN  (default value: 0)

This controls how many child processes the PHP process spawns. When the
fastcgi starts, it creates a number of child processes which handle one
page request at a time. Value 0 means that PHP willnot start additional
processes and main process will handle FastCGI requests by itself. Note that
this process may die (because of PHP_FCGI_MAX_REQUESTS) and it willnot
respawned automatic. Values 1 and above force PHP start additioanl processes
those will handle requests. The main process will restart children in case of
their death. So by default, you will be able to handle 1 concurrent PHP page
requests. Further requests will be queued. Increasing this number will allow
for better concurrency, especially if you have pages that take a significant
time to create, or supply a lot of data (e.g. downloading huge files via PHP).
On the other hand, having more processes running will use more RAM, and letting
too many PHP pages be generated concurrently will mean that each request will
be slow.

PHP_FCGI_MAX_REQUESTS (default value: 500)

This controls how many requests each child process will handle before
exitting. When one process exits, another will be created. This tuning is
necessary because several PHP functions are known to have memory leaks. If the
PHP processes were left around forever, they would be become very inefficient.
PHP 4.x README.FastCGI
There are a few tuning parameters that can be tweaked to control the
performance of FastCGI PHP. The following are environment variables that can
be set before running the PHP binary:

PHP_FCGI_CHILDREN  (default value: 8)

This controls how many child processes the PHP process spawns. When the
fastcgi starts, it creates a number of child processes which handle one
page request at a time. So by default, you will be able to handle 8
concurrent PHP page requests. Further requests will be queued.
Increasing this number will allow for better concurrency, especially if you
have pages that take a significant time to create, or supply a lot of data
(e.g. downloading huge files via PHP). On the other hand, having more
processes running will use more RAM, and letting too many PHP pages be
generated concurrently will mean that each request will be slow.

PHP_FCGI_MAX_REQUESTS (default value: 500)

This controls how many requests each child process will handle before
exitting. When one process exits, another will be created. This tuning is
necessary because several PHP functions are known to have memory leaks. If the
PHP processes were left around forever, they would be become very inefficient.

Les sources de la version PHP 5.3.2 : cgi_main.c

if (fastcgi) {
		/* How many times to run PHP scripts before dying */
		if (getenv("PHP_FCGI_MAX_REQUESTS")) {
			max_requests = atoi(getenv("PHP_FCGI_MAX_REQUESTS"));
			if (max_requests < 0) {
				fprintf(stderr, "PHP_FCGI_MAX_REQUESTS is not valid\n");
				return FAILURE;
			}
		}
 
		/* make php call us to get _ENV vars */
		php_php_import_environment_variables = php_import_environment_variables;
		php_import_environment_variables = cgi_php_import_environment_variables;
 
		/* library is already initialized, now init our request */
		fcgi_init_request(&request, fcgi_fd);
 
#ifndef PHP_WIN32
	/* Pre-fork, if required */
	if (getenv("PHP_FCGI_CHILDREN")) {
		char * children_str = getenv("PHP_FCGI_CHILDREN");
		children = atoi(children_str);
		if (children < 0) {
			fprintf(stderr, "PHP_FCGI_CHILDREN is not valid\n");
			return FAILURE;
		}
		fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, children_str, strlen(children_str));
		/* This is the number of concurrent requests, equals FCGI_MAX_CONNS */
		fcgi_set_mgmt_var("FCGI_MAX_REQS",  sizeof("FCGI_MAX_REQS")-1,  children_str, strlen(children_str));
	} else {
		fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, "1", sizeof("1")-1);
		fcgi_set_mgmt_var("FCGI_MAX_REQS",  sizeof("FCGI_MAX_REQS")-1,  "1", sizeof("1")-1);
	}
  1. If you are using a dynamic application environment, make sure that PHP_FCGI_CHILDREN is always set to 0; that way, PHP will never try to manage worker threads.
  2. If you are using a static environment, decide where you're going to control it and make it clear in the comments in your httpd.conf so you remember six months later!
  3. Don't make too many PHP threads; usually your machine will die of CPU overload if you try to do too much work in the threads; allow httpd to buffer the network requests. More worker threads and CPU threads in your machine is usually counter-productive.
Software caused connection abort: mod_fcgid: ap_pass_brigade failed in handle_request function
FastCGI Process Manager (FPM) SAPI

FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features (mostly) useful for heavy-loaded sites.

Configuration de FPM : FPM utilise la syntaxe php.ini pour son propre fichier de configuration - php-fpm.conf.

  • PHP 5.3.3 inclus : FastCGI Process Manager (FPM) SAPI, voir le ChangeLog et Request for Comments: FPM SAPI inclusion
    • PHP 5.3.3 Added FastCGI Process Manager (FPM) SAPI. (Tony)
    • PHP 5.3.2 Fixed bug #50168 (FastCGI fails with wrong error on HEAD request to non-existant file). (Dmitry)
    • PHP 5.3.1 Fixed bug #27051 (Impersonation with FastCGI does not exec process as impersonated user). (Pierre)
    • PHP 5.3.0
      • Added ".htaccess" style user-defined php.ini files support for CGI/FastCGI.
      • Improved and cleaned CGI code:
        • FastCGI is now always enabled and cannot be disabled. See sapi/cgi/CHANGES for more details. (Dmitry)
        • Added CGI SAPI -T option which can be used to measure execution time of script repeated several times. (Dmitry)
      • Fixed bug #45786 (FastCGI process exited unexpectedly). (Dmitry)
    • PHP 5.2.2 Fixed bug #40286 (PHP fastcgi with PHP_FCGI_CHILDREN don't kill children when parent is killed). (Dmitry)
    • PHP 5.2.0 Improved FastCGI SAPI: (Dmitry)
      • Removed source compatibility with libfcgi.
      • Optimized access to FastCGI environment variables by using HashTable instead of linear search.
      • Allowed PHP_FCGI_MAX_REQUESTS=0 that assumes no limit.
      • Allowed PHP_FCGI_CHILDREN=0 that assumes no worker children. (FastCGI requests are handled by main process itself)
SERVEUR_WEB_PHP:~# apt-cache search php- | grep binary
php5-cgi - server-side, HTML-embedded scripting language (CGI binary)
php5-fpm - server-side, HTML-embedded scripting language (FPM binary)
SERVEUR_WEB_PHP:~# dpkg -l | grep php
ii  libapache2-mod-php5                 5.3.3-0.dotdeb.0         server-side, HTML-embedded scripting language (Apache 2 module
ii  php5                                5.3.3-0.dotdeb.0         server-side, HTML-embedded scripting language (metapackage)
ii  php5-cgi                            5.3.3-0.dotdeb.0         server-side, HTML-embedded scripting language (CGI binary)
ii  php5-cli                            5.3.3-0.dotdeb.0         command-line interpreter for the php5 scripting language
ii  php5-common                         5.3.3-0.dotdeb.0         Common files for packages built from the php5 source

Environement

SERVEUR_WEB_PHP:/var/www# apache2ctl -version
Server version: Apache/2.2.9 (Debian)
Server built:   Nov 14 2009 21:07:23

SERVEUR_WEB_PHP:/var/www# php -version
PHP 5.3.2-0.dotdeb.1 with Suhosin-Patch (cli) (built: Mar  9 2010 11:42:01)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

SERVEUR_WEB_PHP:/var/www# dpkg -l | grep cgi
ii  libapache2-mod-fcgid                1:2.2-1                    an alternative module compat with mod_fastcg
ii  php5-cgi                            5.3.2-0.dotdeb.1           server-side, HTML-embedded scripting languag

SERVEUR_WEB_PHP:/var/www# dpkg -l | grep php
ii  libapache2-mod-php5                 5.3.2-0.dotdeb.1           server-side, HTML-embedded scripting languag
ii  php5                                5.3.1-0.dotdeb.1           server-side, HTML-embedded scripting languag
ii  php5-cgi                            5.3.2-0.dotdeb.1           server-side, HTML-embedded scripting languag
ii  php5-cli                            5.3.2-0.dotdeb.1           command-line interpreter for the php5 script
ii  php5-common                         5.3.2-0.dotdeb.1           Common files for packages built from the php
ii  php5-curl                           5.3.2-0.dotdeb.1           CURL module for php5
ii  php5-gd                             5.3.2-0.dotdeb.1           GD module for php5
ii  php5-ldap                           5.3.2-0.dotdeb.1           LDAP module for php5
ii  php5-mcrypt                         5.3.2-0.dotdeb.1           MCrypt module for php5
ii  php5-mysql                          5.3.2-0.dotdeb.1           MySQL module for php5
ii  php5-suhosin                        5.3.2-0.dotdeb.1           suhosin module for php5
ii  php5-xmlrpc                         5.3.2-0.dotdeb.1           XML-RPC module for php5
ii  php5-xsl                            5.3.2-0.dotdeb.1           XSL module for php5

SERVEUR_WEB_PHP:/var/www# dpkg -l | grep apache
ii  apache2                             2.2.9-10+lenny6            Apache HTTP Server metapackage
ii  apache2-mpm-prefork                 2.2.9-10+lenny6            Apache HTTP Server - traditional non-threade
ii  apache2-suexec                      2.2.9-10+lenny6            Standard suexec program for Apache 2 mod_sue
ii  apache2-utils                       2.2.9-10+lenny6            utility programs for webservers
ii  apache2.2-common                    2.2.9-10+lenny6            Apache HTTP Server common files
ii  libapache2-mod-fcgid                1:2.2-1                    an alternative module compat with mod_fastcg
ii  libapache2-mod-php5                 5.3.2-0.dotdeb.1           server-side, HTML-embedded scripting languag

SERVEUR_WEB_PHP:/var/log/apache2# vim /var/www/php-fcgi-scripts/userweb1/php-fcgi-starter

#!/bin/sh
PHPRC=/etc/php5/cgi/
export PHPRC
export PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_CHILDREN=8
exec /usr/lib/cgi-bin/php
http://mon.site.web/phpinfo.php
Environment
Variable	Value
PHPRC 	/etc/php5/cgi/
PHP_FCGI_CHILDREN 	8
PATH 	/usr/local/bin:/usr/bin:/bin
PWD 	/var/www/php-fcgi-scripts/userweb1
SHLVL 	0
PHP_FCGI_MAX_REQUESTS 	5000

Configuration du mod_fcgi

mod_fcgid

  • IdleScanInterval FcgidIdleScanInterval
  • IdleTimeout FcgidIdleTimeout
  • IPCCommTimeout FcgidIOTimeout
  • IPCConnectTimeout FcgidConnectTimeout

FcgidIdleScanInterval (anciennement IdleScanInterval)

  • FcgidIdleScanInterval Directive
  • Description: scan interval for idle timeout process
  • Syntax: FcgidIdleScanInterval seconds
  • Default: FcgidIdleScanInterval 120
  • Context: server config
  • Status: External
  • Module: mod_fcgid

This is the interval at which the module will search for processes which have exceeded FcgidIdleTimeout or FcgidProcessLifeTime.

FcgidIdleTimeout (anciennement IdleTimeout)

  • FcgidIdleTimeout Directive
  • Description: An idle FastCGI application will be killed after FcgidIdleTimeout
  • Syntax: FcgidIdleTimeout seconds
  • Default: FcgidIdleTimeout 300
  • Context: server config, virtual host
  • Status: External
  • Module: mod_fcgid

Application processes which have not handled a request for this period of time will be terminated, if the number of processses for the class exceeds FcgidMinProcessesPerClass. A value of 0 disables the check.

This idle timeout check is performed at the frequency of the configured FcgidIdleScanInterval.

This setting will apply to all applications spawned for this server or virtual host. Use FcgidCmdOptions to apply this setting to a single application.

FcgidIOTimeout (anciennement IPCCommTimeout)

  • FcgidIOTimeout Directive
  • Description: Communication timeout to FastCGI server
  • Syntax: FcgidIOTimeout seconds
  • Default: FcgidIOTimeout 40
  • Context: server config, virtual host
  • Status: External
  • Module: mod_fcgid

This is the maximum period of time the module will wait while trying to read from or write to a FastCGI application. Note

The FastCGI application must begin generating the response within this period of time. Increase this directive as necessary to handle applications which take a relatively long period of time to respond.

This setting will apply to all applications spawned for this server or virtual host. Use FcgidCmdOptions to apply this setting to a single application.

FcgidConnectTimeout (anciennement IPCConnectTimeout)

  • FcgidConnectTimeout Directive
  • Description: Connect timeout to FastCGI server
  • Syntax: FcgidConnectTimeout seconds
  • Default: FcgidConnectTimeout 3
  • Context: server config, virtual host
  • Status: External
  • Module: mod_fcgid

This is the maximum period of time the module will wait while trying to connect to a FastCGI application on Windows. (This directive is not respected on Unix, where AF_UNIX defaults will apply.)

This setting will apply to all applications spawned for this server or virtual host. Use FcgidCmdOptions to apply this setting to a single application.

php_value FCGI

<virtualHost *:80>
 php_value register_globals on
</VirtualHost>
 # /etc/init.d/apache2 restart
Restarting web server: apache2We failed to correctly shutdown apache, so we're now killing all running apache processes. This is almost certainly suboptimal, so please make sure your system is working as you'd expect now! (warning).
... waiting .Syntax error on line 24 of /etc/apache2/sites-enabled/mysite:
Invalid command 'php_value', perhaps misspelled or defined by a module not included in the server configuration failed!

Solution

# vim "/var/www/php-fcgi-scripts/mysite/php-fcgi-starter"
#!/bin/sh
PHPRC=/etc/php5/cgi/
export PHPRC
export PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_CHILDREN=8
exec /usr/lib/cgi-bin/php -d register_globals="1"

Ressources

Changing php_value for one vhost in fcgi...

What's in /var/www/php-cgi-scripts/web4/php-cgi-starter? et ajout de directive PHP dans le le php-cgi-starter

My experience with Apache 2.2, fcgi...
For example enable register_globals on (apache2) / .htaccess :
php_value register_globals 1
Only if you are running php as a apache module, that do not work in suexec.
Why php_value directives for php.ini set in .htaccess fail when php is running as cgi or fcgi

Those are Apache directives, but in CGI mode Apache calls the php binary, which turn reads php.ini. Since the binary doesn’t read httpd.conf it has no effect on PHP. As PHP isn’t loaded into Apache, Apache doesn’t know what to do with the directives and borks.