Contexte
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 :
- Configuration initiale : apache + module mod_php
- Changement de mode de fonctionnement PHP : apache + php5-fpm
- Changement de serveur http : nginx + php5-fpm
Note : toutes les commandes sont données ici pour une plate-forme de souche Debian (Debian / Ubuntu), utilisant les commandes apt-get
.
Configuration initiale
Installation
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).
Paramétrage
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.
Tests de charge / top
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.
Utilisation de PHP en mode FPM
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.
Installation
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
Paramétrage
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éfaut
Il 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.
Tests de charge / top
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
Paramétrage du nombre de clients PHP
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
Remplacement du serveur apache par nginx
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 !