- MPM Worker : Quelques processus lancent des threads. Une requête par thread. Plus rapide.
- MPM Prefork : Une requête par processus. Isolation des requêtes, compatible avec bibliothèques non thread-safe.
- MPM ITK : Variante de Prefork permettant l'utilisation de plusieurs utilisateurs UNIX. Rare mais utilisé à VIA.
- Et bien d'autres ! (ex: MPM Event)
Configuration
Sous la forme attribut – valeur
Sections imbriquées pour spécifier la portée des options
Timeout 10
<IfModule mpm_prefork_module>
StartServers 20
MinSpareServers 50
MaxSpareServers 100
ServerLimit 1024
MaxClients 1024
MaxRequestsPerChild 5000
</IfModule>
<IfModule mpm_worker_module>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxClients 150
MaxRequestsPerChild 0
</IfModule>
Configuration
/etc/apache2/apache2.conf est très bien commenté
Configuration minimale
Listen 80 # port d'écoute
User www-data # Utilisateur sous lequel tourne Apache
Group www-data # Groupe sous lequel tourne Apache
DocumentRoot /var/www/my-website # Dossier utilisé comme racine du site web
<Directory /var/www/my-website> # Restriction de la portée à un dossier
Options Indexes # Active l'option d'affichage de l'index de dossier
AllowOverride All # Autorise les .htaccess à changer la configuration
Order allow,deny # Définit la priorité pour les options Allow/Deny
Allow from all # Autorise le dossier à tous
</Directory>
<Directory /> # Restriction forte sur le reste des dossiers
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
</Directory>
Le multi-domaine
Comment faire quand on a plusieurs sites web ?
On utilise des VirtualHosts
On va déclarer un site web par VirtualHost
Qui correspondra à un fichier dans sites-enabled/
Un VirtualHost donné répondra uniquement à des requêtes avec un header Host spécifique
C'est tellement pratique qu'on va faire un VHost même pour un seul site
VirtualHosts
Listen 80
Listen 443
NameVirtualHost *:80 # On déclare une "interface" qui sera utilisée par des VHosts
NameVirtualHost 127.0.0.1:443 # Peut aussi s'attacher à une IP
<VirtualHost *:80> # On configure un VHost sur une des interfaces
ServerName site0.localhost # Host pour lequel ce VHost va répondre
DocumentRoot /var/www/site0 # Racine de ce VHost
</VirtualHost>
<VirtualHost *:80>
ServerName site1.localhost
DocumentRoot /var/www/site1
</VirtualHost>
<VirtualHost 127.0.0.1:443>
DocumentRoot /var/www/secure
</VirtualHost>
Quand une requête arrivant sur une interface de VHost ne trouve pas de VHost à ServerName correspondant, c'est le premier déclaré qui l'emporte. (cf. 000-default)
Exemple plus complet
<VirtualHost *:80>
ServerName my.ecp.fr
ServerAlias myecp-prod.via.ecp.fr myecp-prod myecp.via.ecp.fr
DocumentRoot /var/www/myecp
ServerAdmin support@my.ecp.fr
ErrorLog /var/log/apache2/myecp/error.log
CustomLog /var/log/apache2/myecp/access.log combined
LogLevel info
<Directory /var/www/myecp/web>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ app.php [QSA,L]
AllowOverride None
Options FollowSymLinks
</Directory>
Header set X-Custom-Header "Content delivered in %D ms"
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
</Directory>
Les modules
Il y en a beaucoup beaucoup ! Exemple de ceux à VIA.
mod_autoindex | Affiche l'index des dossiers |
mod_rewrite | Réecriture d'URL |
mod_header | Modifier les headers |
mod_deflate | Compression gzip des données |
mod_status | Page de status des processus Apache |
mod_ssl | Faire du HTTPS |
mod_ldap | Authentification HTTP via LDAP |
mod_userdir | Active les "people" /~username/ |
mod_php5 | Incorpore un interpréteur PHP |
mod_cgi | Interface CGI |
mod_fcgi | Interface FastCGI |
Contenu dynamique
Idée : utiliser un langage de programmation (PHP, Python, Ruby, Perl...) pour générer du contenu dynamiquement
Deux solutions :
- Intégrer un interpréteur directement dans Apache
- Faire fonctionner le programme à part, et communiquer avec
Interpréteur intégré
Les processus d'Apache qui répondent aux requêtes intègre un interpréteur directement
En pratique, c'est la méthode classique pour PHP (mod_php)
Mais existe aussi pour d'autres (mod_ruby, mod_python)
Avantages : très simple à mettre en place et gérer
Inconvénients : plus lourd en mémoire, uniquement mpm-prefork
Exécution indépendante
Le serveur HTTP gère et communique avec le programme
- CGI : Le programme est exécuté pour chaque requête et échange avec le serveur selon CGI. mod_cgi.
- FCGI : FastCGI. Même principe sauf que le programme tourne en boucle, de manière indépendante. Bien plus rapide. mod_fcgid.
Quelques interfaces spécifiques à un langage (WSGI, Rack...).
Avantages : Plus léger en mémoire, compatibilité MPM, permissions UNIX différentes, autorise des middlewares
Inconvénients : Plus complexe à mettre en place, plus lent (PHP)
Setup classique avec Apache2
PHP :
Apache2 + mod_php
Python :
Apache2 + gunicorn ou uwsgi + mod_proxy
Apache2 + mod_wsgi
Ruby :
Apache2 + unicorn + mod_proxy
Apache2 + mod_passenger
Optimisation Apache
Connexion persistante HTTP : multiple requête sur unique socket TCP
KeepAlive On
MaxKeepAliveRequests 100000
KeepAliveTimeout 4
MPM : à calculer à partir de sa RAM et sa variation de visiteurs.
StartServers 200 # Nombre de processus initiaux
MinSpareServers 50 # Spawn beaucoup de processus d'un coup coûte cher
MaxSpareServers 100 # Le Spare sert de tampon pour éviter ça
ServerLimit 1024 # == MaxClients
MaxClients 1024 # Nombre max de processus
MaxRequestsPerChild 5000 # À garder élevé
Misc.
HostnameLookups Off # Pas de résolution DNS pour les logs
AllowOverride None # Ne cherche pas de .htaccess
ServerTokens Prod # Réduit la taille du header "Server"
ServerSignature Off # Moins d'info dans les pages d'erreur
TraceEnable Off # Fonction de test/debug
Option FollowSymLinks # Ne pas vérifier si un élément est un symlink ou non. À définir au niveau d'un Directoy global.
Performances HTTP
-
Réduire le nombre de requêtes HTTP en réduisant le nombre d'éléments
- Concaténation CSS/JS : Concaténer tous les fichiers CSS ou JS dans un seul et unique fichier.
- CSS Sprites : Même idée avec des images. Inclure plusieurs icônes dans une même image mais n'afficher qu'un bout par CSS.
-
CDN : Utiliser des Content Delivery Network (des serveurs rapides spécifiques pour le contenu statique). Exemple : Utiliser jQuery hébergé par Google.
-
DNS : le navigateur ne fait pas plus de 8-10 requêtes simultanées par DNS. Possibilité de distribuer le contenu sur plusieurs DNS (ex: les tuiles des cartes Google Maps).
-
gzip, minified code : réduire la taille des données en utilisant la compression HTTP gzip (mod_deflate) ou en allégeant le code (virer les espaces, ...)
Performances applicatives
- Un code propre et rapide : Limiter les opérations lentes (BDD, API externes, opérations complexes). Les exécuter en asynchrone au besoin.
- Un environnement optimal : Dernières versions logicielles. Pour PHP, installer APC.
- Cache applicatif : Pour les contenus souvent calculer et qui change peu, ne pas hésiter à les mettre en cache dans le code même (exemple : la liste des dernières news. N'expirer le cache qu'à la création d'une nouvelle. Réduit le nombre de requêtes BDD).
- Rendu : Contenu HTML et Javascript pas trop dégeu ! Quelques guidelines.
Cache HTTP
Super important !
- Bien comprendre les processus de validation et d'expiration. Très documenté sur la toile.
- Le configurer proprement sous Apache (mod_headers, mod_expires)
- Bonus : Utiliser Varnish. Cache intermédiaire entre le client et Apache.
Debug/Administration
Activer mod_status
Aller voir les logs
Utiliser Munin
Ou encore mieux, Datadog <3
THE END