Afin d'améliorer les performances et limiter la consommation mémoire, on va passer une configuration apache + mod_php en nginx + php-fpm.
Ceci va se faire en plusieurs étapes, qui peuvent être mises en place progressivement :
Note : toutes les commandes sont données ici pour une plate-forme de souche Debian (Debian / Ubuntu), utilisant les commandes apt-get.
L'installation "par défaut" de apache + php s'effectue simplement via les commandes :
apt-get install apache2 apache2-mpm-prefork apache2-utils
Ceci installe le serveur http apache2 ainsi que les utilitaires (apache2ctl).
On installe ensuite php5 et quelques modules utiles :
php5 php5-gd php5-mysql php5-curl
Le module php5-mysql n'est utile que pour l'utilisation de php avec MySQL (ce qui est souvent le cas).
Le VirtualHost apache est défini de la manière suivante :
<Virtualhost *:80 >
ServerAdmin webmaster@localhost
ServerName lxc.test.local
DocumentRoot /var/www/lxc
<Directory /var/www/lxc>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
# Inclusion du .htccess de drupal (si necessaire)
Include /var/www/lxc/.htaccess
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error_lxc.log
LogLevel info
CustomLog ${APACHE_LOG_DIR}/access_lxc.log combined
</Virtualhost>
Il s'agit d'un site tournant sous Drupal. On inclut le fichier .htaccess qui se trouve à la racine du site, et on positionne le AllowOverride None pour améliorer les performances.
Ceci évite au serveur Apache de parser chaque répertoire à la recherche d'un fichier .htaccess.
Il faut que le module rewrite soit activé. Ceci est fait via :
a2enmod rewrite
Dans cette configuration avec le module mod_php activé, les process apache consomment entre 32 et 55 Mo de RAM.
Avec la configuration par défaut, si on lance une commande de test : ab -c20 -n1000 http://testgeo.test.local/carte, soit un millier de requêtes avec 20 requêtes concurrentes, on observe le comportement suivant :
Tasks: 48 total, 23 running, 25 sleeping, 0 stopped, 0 zombie
%Cpu(s): 80,9 us, 18,1 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 1,0 si, 0,0 st
KiB Mem: 4037712 total, 3786172 used, 251540 free, 73920 buffers
KiB Swap: 4881404 total, 40612 used, 4840792 free, 778428 cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
305 mysql 20 0 1310m 83m 7636 S 7,0 2,1 0:02.09 mysqld
525 www-data 20 0 326m 36m 22m S 6,7 0,9 0:01.74 apache2
522 www-data 20 0 325m 32m 20m R 6,3 0,8 0:01.75 apache2
358 www-data 20 0 326m 32m 18m R 6,7 0,8 0:01.41 apache2
594 www-data 20 0 326m 32m 18m R 7,0 0,8 0:00.91 apache2
600 www-data 20 0 326m 32m 18m R 7,0 0,8 0:00.86 apache2
604 www-data 20 0 326m 32m 18m R 7,0 0,8 0:00.86 apache2
607 www-data 20 0 326m 32m 18m R 7,0 0,8 0:00.86 apache2
592 www-data 20 0 326m 31m 18m R 6,7 0,8 0:00.91 apache2
582 www-data 20 0 325m 31m 18m R 6,3 0,8 0:01.56 apache2
602 www-data 20 0 325m 30m 18m R 6,7 0,8 0:00.84 apache2
605 www-data 20 0 325m 30m 18m R 6,0 0,8 0:00.83 apache2
359 www-data 20 0 323m 30m 19m R 5,3 0,8 0:01.75 apache2
528 www-data 20 0 323m 30m 20m R 6,7 0,8 0:01.72 apache2
595 www-data 20 0 324m 30m 18m R 6,3 0,8 0:00.94 apache2
360 www-data 20 0 323m 30m 19m S 6,3 0,8 0:01.76 apache2
593 www-data 20 0 324m 30m 18m R 6,3 0,8 0:00.95 apache2
588 www-data 20 0 323m 29m 18m R 6,0 0,7 0:01.05 apache2
527 www-data 20 0 323m 29m 18m R 6,7 0,7 0:01.37 apache2
543 www-data 20 0 323m 29m 18m R 7,0 0,7 0:01.34 apache2
554 www-data 20 0 323m 29m 18m S 6,7 0,7 0:01.22 apache2
555 www-data 20 0 323m 29m 18m R 6,7 0,7 0:01.23 apache2
603 www-data 20 0 323m 28m 18m R 6,3 0,7 0:00.83 apache2
606 www-data 20 0 322m 27m 18m R 6,0 0,7 0:00.82 apache2
610 www-data 20 0 322m 27m 18m R 6,0 0,7 0:00.71 apache2
583 www-data 20 0 320m 26m 18m S 6,0 0,7 0:01.19 apache2
589 www-data 20 0 320m 26m 18m S 5,3 0,7 0:01.07 apache2
601 www-data 20 0 320m 26m 18m S 7,0 0,7 0:00.87 apache2
611 www-data 20 0 320m 26m 18m R 6,7 0,7 0:00.43 apache2
340 root 20 0 319m 15m 9844 S 0,0 0,4 0:00.05 apache2
Le mode prefork utilisé par Apache avec le module mod_php implique de lancer un processus pour traiter chaque requête concurrente. Par défaut, le nombre de clients est limité à 150, ce qui explique ici la présence d'une trentaine de processus, qui se réservent chacun environ 30 Mo de mémoire.
Le mode FPM (Fast Process Management) de PHP permet de séparer le serveur http et le serveur PHP, à la manière de ce qui est fait pour les serveurs d'application Java.
De ce fait, on allège l'empreinte mémoire du serveur http, et on peut contrôler plus facilement les ressources utilisées par PHP.
L'installation de PHP5-FPM doit également comprendre la désinstallation du module mpm-prefork pour Apache, et la désactivation du module mod_php.
On installe ainsi le package php5-fpm, le module apache mpm-worker, qui utilise des threads plutôt que des process, et la librairie fastCGI pour Apache.
apt-get install php5-fpm apache2-mpm-worker libapache2-mod-fastcgi
apt-get remove apache2-prefork
a2enmod actions fastcgi alias
a2dismod mod_php
On peut laisser le paramétrage de PHP5-FPM par défaut, celui-ci étant défini dans plusieurs fichiers :
/etc/php5/fpm/php.ini : fichier d'initialisation PHP/etc/php5/fpm/php-fpm.conf : fichier de configuration FPM/etc/php5/fpm/pool.d/www.conf : fichier de configuration du pool par défautIl faut par contre ajouter un fichier de configuration pour Apache, afin qu'il utilise maintenant FastCGI pour traiter les fichiers PHP.
Ceci peut être fait soit au niveau de chaque VirtualHost, soit globalement. C'est cette option que je présente ici.
Pour ce faire, on crée un nouveau fichier de configuration /etc/apache2/conf.d/php5-fpm.conf, qui contient :
< ifmodule mod_fastcgi.c >
AddHandler php5-fcgi .php
Action php5-fcgi /php5-fcgi
Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi
FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -socket /var/run/php5-fpm.sock -pass-header Authorization
</ifmodule>
Le paramétrage utilise ici un socket Unix pour faire la passerelle entre le serveur http et le serveur PHP-FPM.
Le nom du socket est défini dans le fichier du pool php /etc/php5/fpm/pool.d/www.conf :
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on
; a specific port;
; 'port' - to listen on a TCP socket to all addresses on a
; specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = /var/run/php5-fpm.sock
Note : on peut également utiliser un port TCP. Si on utilise Apache 2.4, c'est d'ailleurs pour l'instant la seule méthode.
On voit également qu'on pourrait séparer le frontal http et le serveur PHP, en communiquant sur un port réseau entre les 2 machines.
Il faut ensuite redémarrer le serveur PHP et le serveur http :
sudo service php5-fpm start
sudo service apache2 start
L'ordre des commandes n'a pas d'importance, même s'il est préférable de démarrer le serveur PHP en premier, et le "frontal" http par la suite.
Avec le paramétrage par défaut, le serveur http fonctionne avec des threads, beaucoup moins gourmands. On remarque que l'on utilise essentiellement les ressources du serveur php, et très peu celles du serveur http. Au total on a 28 tâches, au lieu des 48 dans la configuration initiale.
Tasks: 28 total, 6 running, 22 sleeping, 0 stopped, 0 zombie
%Cpu(s): 79,9 us, 19,3 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,8 si, 0,0 st
KiB Mem: 4037712 total, 3743248 used, 294464 free, 65964 buffers
KiB Swap: 4881404 total, 40632 used, 4840772 free, 893072 cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
335 mysql 20 0 804m 84m 7624 S 6,7 2,1 0:10.10 mysqld
2471 www-data 20 0 288m 40m 21m R 36,3 1,0 0:06.17 php5-fpm
2470 www-data 20 0 281m 33m 21m R 35,9 0,8 0:06.33 php5-fpm
2476 www-data 20 0 281m 29m 18m R 35,9 0,7 0:05.29 php5-fpm
2477 www-data 20 0 279m 27m 18m R 35,6 0,7 0:04.57 php5-fpm
2478 www-data 20 0 276m 24m 18m R 36,9 0,6 0:04.09 php5-fpm
2469 root 20 0 273m 5440 1572 S 0,0 0,1 0:00.04 php5-fpm
2399 www-data 20 0 1256m 4332 1360 S 1,0 0,1 0:00.21 apache2
2398 www-data 20 0 1256m 3824 1208 S 1,0 0,1 0:00.20 apache2
2395 root 20 0 78752 3552 1536 S 0,0 0,1 0:00.02 apache2
221 root 20 0 10188 2912 612 S 0,0 0,1 0:00.00 dhclient
243 root 20 0 50052 2864 2276 S 0,0 0,1 0:00.00 sshd
2396 www-data 20 0 78484 2540 560 S 0,0 0,1 0:00.00 apache2
2397 www-data 20 0 78484 2448 464 S 0,0 0,1 0:00.00 apache2
Dans le fichier/etc/php-fpm.d/www.conf
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
On peut calculer la mémoire utilisée par chaque process fils de PHP-FPM :
ps -ylC php-fpm --sort:rss
La valeur de pm.max_children peut être calculée comme suit :
pm.max_children = RAM dédié au serveur web/php / (taille maximale d'un process)
Par exemple si on a 4 Go de RAM pour PHP, et une taille maximale de 80 Mo :
pm.max_children = 4000 / 80 = 50
Le reste du paramétrage est alors (en dynamic) :
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 20
pm.max_spare_servers = 35
pm.max_requests = 500
Une fois que php5-fpm est en place et activé, il est assez simple d'installer et de configurer nginx en lieu et place de apache. A compléter !