Apache – Linux – MPM Prefork – Optimisation utilisation mémoire et performance


Plus un site WEB est accédé, plus il devient important d’optimiser l’utilisation de la mémoire par Apache tout en assurant la performance de service des requêtes délivrées par le serveur Apache.

Cet article ne se substitue aucunement à la documentation Apache Foundation sur le sujet MPM (Modules Multi-Processus). Il a pour vocation de clarifier l’optimisation des paramètres pas toujours très évidents à calibrer les uns avec les autres

Je me suis trouvée confrontée durant ces dernières semaines à un gros problème de dérive de l’utilisation de la mémoire par Apache. Le serveur en question délivre des requêtes pour environ 40 sites WEB plus ou moins chargés. Certains de ces sites ont des facteurs de charge de requêtes très importants. Bien entendu au fil du temps, le serveur est de plus en plus sollicité, amenant à une revue de configuration du serveur Apache.

Dans ce cas précis, le serveur Apache transmets les requêtes PHP a un serveur PHP-FPM, donc configuré en Fast-CGI. Sans entrer dans le détail de la configuration PHP-FPM, les pools FPM ont été configurés en fonction des besoins.

Le serveur invoqué dans l’optimisation qui a conduit à la rédaction de cet article est doté de 16 vCPU, 128 Go de RAM.

Multi-Process Modules (MPM)

Trois modes de fonctionnement existent pour Apache pour la gestion des requêtes au travers de module de traitements parallèles des requêtes  :

  • mpm_prefork_module
  • mpm_worker_module
  • mpm_event_module

Dans l’ordre, ci-dessus, le module prefork est historique, le worker est plus optimisé que le prefork, le module event est le plus optimisé de tous et normalement le plus efficace. Toutefois quelques tests de performance menés en condition de production ces derniers temps montrent que le module prefork a encore de beaux jours devant lui dépendant du mode de fonctionnement des sites WEB gérés par Apache.

L’article actuel traite spécifiquement du module prefork.

MPM Prefork

Les paramètres invoqués pour l’optimisation du module mpm_prefork sont les suivants (source initiale : Apache Foundation, Apache MPM Prefork) :

  • StartServers
  • MinSpareServers
  • MaxSpareServers
  • MaxRequestWorkers
  • MaxMemFree
  • MaxConnectionsPerChild
  • GraceFulShutdownTimeout
  • ServerLimit

Tous ces paramètres sont forcément liés les uns aux autres et doivent être configurés avec précaution si on ne veut pas se trouver soit avec un serveur engorgé ne traitant pas dans les temps les requêtes, soit avec un serveur qui se met à swapper par une trop grande utilisation mémoire. On pourrait dire comme pour toute optimisation de serveurs que cela pourrait procéder de l’alchimie, mais, comme on a toujours dit, l’informatique n’est pas de la magie.

StartServers

Ce paramètre définit combien de process au niveau système vont être démarrés à l’initialisation d’Apache. Ce paramètre n’a d’importance qu’au démarrage du serveur et n’est ensuite plus utilisé.

Il peut de ce fait être à une valeur faible, même sur un serveur de production. Une valeur de 128 est suffisante au démarrage du serveur Apache, les autres paramètres agissant immédiatement derrière sur la montée en charge du serveur Apache.

MinSpareServers

Un serveur de spare est, en français, un serveur de secours. Dans le cas d’Apache, c’est un processus démarré au niveau du système d’exploitation et « dormant ».

Le serveur Apache démarrera autant de serveurs (processus Linux) qu’il faut pour avoir à disposition toujours ce nombre minimum de serveurs de secours.

!!! ATTENTION !!! Tout processus démarré au niveau du système d’exploitation prend d’office des ressources du système même s’il ne fait rien en apparence. Le système est obligé de le faire passer dans son ordonnanceur de processus (process scheduler) pour constater qu’il n’a rien à exécuter. Il oblige donc à un changement de contexte pour savoir s’il y a quelque chose à traiter (context switch en langage système d’exploitation). Chaque changement de contexte implique une utilisation, même faible, des ressources du serveur. Plus le nombre de serveurs de secours est important, plus le système devra changer souvent de contexte pour traiter des serveurs de requêtes inactifs. Un trop grand nombre de serveurs inactifs peut avoir des conséquences très lourdes pour les performances du serveur à tous les niveaux : mémoire, ressource CPU.

Une bonne valeur pour ce paramètre est donc une valeur très faible. Après pas mal de tests, il s’est avéré qu’une valeur de 16 serveurs inactifs en continu n’a pas d’effet négatif sur les performances du serveur.

MaxSpareServers

Ce paramètre définit combien de processus serveur de requêtes au maximum peuvent être maintenus en vie pour utilisation ultérieure par Apache. Si le nombre de processus inactifs est supérieur à ce nombre, Apache arrête autant de processus inactifs que nécessaire afin de rejoindre la valeur de MaxSpareServers.

!!! ATTENTION !!! La même mise en garde que pour MinSpareServers est de mise. Un trop grand nombre de serveurs de secours inactifs pourra avoir de très lourdes conséquences sur les performances globales du serveur à tous les niveaux : mémoire, ressource CPU.

Ce paramètre a une action directe sur les ressources systèmes disponibles. Chaque processus inactif arrêté libère des ressources système pouvant être utiles à d’autres tâches.

Dans le cas présent, la valeur de 32 serveurs inactifs maximum a été définie.

ServerLimit

Ce paramètre est de loin le plus important sur un fonctionnement 24x7x365. Il définit le nombre maximum de processus pouvant être démarrés par Apache. La documentation à son sujet n’est pas très claire. Il est mis en relation avec le paramètre MaxRequestWorkers qui lui aussi est très important mais ne parle pas tout à fait de la même chose.

Il est crucial de donner une limite haute au nombre de processus démarrés par Apache. Il ne faudrait pas qu’un nombre trop important de processus démarrés puisse aboutir à une saturation globale des ressources, qu’elles soient mémoire ou charge (file d’attente de processus par processeur/cœur virtuel ou physique).

Sa valeur peut être fixée selon une règle simple : Nombre maximum de process actifs voulus + Nombre minimum de serveur de secours –> MaxRequestWorkers + MinSpareServers.

Sur un serveur doté de 16 vCPU, la limite haute permettant un fonctionnement fluide du serveur a été fixée à 528 (512 + 16).

MaxRequestWorkers

Ce paramètre s’avère être lui aussi crucial pour la performance. Il définit le nombre maximum de requêtes pouvant être traitées simultanément par le serveur Apache. Il guide aussi la valeur de ServerLimit. ServerLimit ne peut être inférieur à MaxRequestWorkers.

Dans le cas présent de ce serveur, le maximum est fixé à 512, sachant qu’il a un impact direct sur ServerLimit.

MaxConnectionsPerChild

Ce paramètre ne doit surtout pas être laissé à zéro sur des serveurs à forte activité. S’il est laissé à zéro, alors un processus enfant pourra traiter un nombre illimité de connexions (sessions dans les faits) sans jamais être arrêté. Ceci peut avoir pour conséquence l’apparition de fuites mémoire.

Ce paramètre est configuré à 8192, ce qui permet aussi de ne pas réinitialiser trop souvent les serveurs de requêtes.

MaxMemFree et GracefulShutdownTimeOut

Ces deux paramètres sont à configurer dans des cas de serveurs disposant de peu de mémoire et de peu de ressources processeur. Dans le cas contraire ils peuvent être laissés en valeur par défaut, sans limite.

En conclusion

Lors de la configuration d’un serveur Apache en environnement Linux, ou dans le cas d’une mise en place d’optimisations suite à des problèmes de performance constatés dans le traitement des requêtes par le serveur Apache, il ne faut pas hésiter à optimiser ces paramètres. Ils peuvent drastiquement augmenter la performance d’Apache et surtout permettre une utilisation optimale des ressources du serveur Linux.