Dimensionnement mémoire d'un serveur web Apache
Dimensionnement d'un serveur web apache
De nos jours, mettre en place un serveur web est une tache relativement facile. La plupart des sites n'ayant pas pour vocation de remplacer yahoo et google, et la capacité des machines étant en hausse constante, une installation de base de apache suffit pour la plupart des particuliers.
Néanmoins, dans un contexte professionnel, ça ne suffit généralement pas. Nous allons donc voir une méthode pour déterminer comment régler apache. Ce guide ne prétend pas permettre de répondre à tout les problémes, mais peut servir de base à des changements en finesse.
Présentation de la machine et des besoins
Notre exemple est tiré d'un cas réel. Le serveur en question tourne sur un noyau 2.6.16, avec un bi-xeon 2,8 Ghz, 1 Go de ram, et 2 Go de swap. La version d'apache est une version 2.0.54. Le serveur a une tache trés simple, c'est de servir de portail pour authentifier les utilisateurs en dehors du réseau intranet. Chaque utilisateur se connecte, reçoit un cookie, et surfe sur les pages du site. Les utilisateurs sont dans une base ldap, les cookies dans une base postgresql, et le portail est écrit en mod_python. Pour diverses raisons, apache utilise le module prefork, sans thread, car les tests ont montré des erreurs dûes au code non multithread du portail ( ou d'une bibliothèque associée ). Ça tombe bien, car cela simplifie le calcul de dimensionnement.
Principes généraux sur l'optimisation d'apache
De nombreux documents existent sur le sujet, comme : http://httpd.apache.org/docs/2.0/misc/perf-tuning.html http://www.jacobian.org/writing/2005/dec/12/django-performance-tips/ http://virtualthreads.blogspot.com/2006/01/tuning-apache-part-1.html
Je vous conseille de les lire en entier, et d'essayer de les comprendre.
Pour résumer, le principe général de l'optimisation est le suivant : pour chaque serveur, il y a 4 ressources ( ou plus ) :
- la ram
- le disque
- le processeur
- la bande passante
Il faut identifier la ressource qui coincera la première, et si besoin, agir à ce niveau. Dans le cas d'apache, ça dépend de ce qui est servi. Un site avec des pages complexes en php va utiliser du cpu, ou de la ram. Un site proposant des films ou des vidéos va surtout utiliser le disque ou la bande passante.
Dans le cas de notre exemple, le site n'utilise pas le disque, ne fait pas d'opération coûteuse en temps CPU, et n'est pas limité par le réseau.
Pour le savoir, c'est trés simple, il suffit d'utiliser ab ( apache benchmark ), et de surveiller les ressources, avec htop, iostat, ntop, etc. Je vous conseille de lire cette article pour avoir une vue rapide des outils utilisés : http://www.redhat.com/magazine/011sep05/features/tools/ ( ou le début de ce document http://www.lemis.com/grog/Papers/Debug-tutorial/tutorial.pdf )
Dans notre exemple, la supervision des ressources vient de munin, et le benchmark d'un moteur de recherche interne mal réglé, poussant le serveur au delà des limites de la configuration par défaut.
Donc, après "benchmark", nous avons constaté que la limitation principal, ce fut le nombre de processus.
La configuration, quasiment par défaut, contient :
<IfModule prefork.c>
# nombre maximum de processus au repos
MaxSpareServers 10
# nombre minimum de processus au repos
MinSpareServers 5
# nombre maximum de processus
MaxClients 20
# nombre de requêtes avant de relancer le processus
MaxRequestsPerChild 1000
# nombre de serveurs lancés au démarrage
StartServers 5
</IfModule>
Ce qui nous limite à 20 processus simultanés.
Comme indiqué dans la documentation d'apache, c'est un protection. Permettre de lancer un nombre illimité de serveur ne sert à rien, car il y a toujours une ressource qui va manquer. Donc, cela permet de ménager la machine, pour intervenir en cas de probléme.
Néanmoins, ces valeurs ne sont pas optimales, et nous allons voir comment les augmenter, et de combien.
Un peu de calcul
La mémoire, sous linux et sans doute sous d'autres unix, voir d'autres OS, est toujours occupé au maximum. Soit les processus qui tournent l'utilisent, soit le noyau se sert de ceci comme cache.
Notre première étape va donc être de calculer quel part est prise par le cache, via la commande free :
misc@teferi# free total used free shared buffers cached Mem: 1033980 978420 55560 0 83672 729744 -/+ buffers/cache: 165004 868976 Swap: 1999192 284 1998908
Soit, ~ 730 Mo de cache ( en dessous de cached ), sur un total de 1000 Mo. Parmi les 730 Mo, j'ai décidé d'en mettre la moitié pour apache, soit ~ 360 Mo. On peut en mettre plus, si le serveur ne fait que ça, mais je préfère laisser de la place pour d'autres taches, et 360 Mo seront largement suffisant, comme nous verrons par la suite.
La deuxiéme partie, c'est de savoir combien de serveur en plus peut on mettre dans 360 Mo. Le calcul est simple, on prends la mémoire prise par un serveur, et on divise. Jusqu'ici, tout va bien, mais ça ne va pas durer.
La gestion de la mémoire sous linux est assez complexe. Les zones mémoires sont partagées entre les processus si elles sont identiques, les zones peuvent être en swap ou en mémoire, et d'une maniére général, les outils sont verbeux.
Pour déterminer la taille utilisée par un client, le premier pas est d'utiliser ps, pour voir les processus. C'est ainsi que j'ai vu que chaque serveur apache se connecte directement à postgresql, il faut donc déterminer la taille des 2 processus.
Je me suis basé sur ce guide ( http://www.kdedevelopers.org/node/1445 ), et j'ai obtenu les chiffres suivants grâce à 'top' :
Un processus apache prends en moyenne : data(DATA) 7000, shared(SHR) 3500, resident(RES) 10000, virtual(VIRT) 16000
Un processus postgresql prends : data(DATA) 1500, shared(SHR) 2800, resident(RES) 4000, virtual(VIRT) 17000
VIRT n'est pas utile dans notre calcul, c'est la mémoire demandé, pas la mémoire alloué.
SHR, c'est de la mémoire partagée. Comme nos processus sont identiques, c'est de la mémoire qui ne compte que pour le premier processus. Donc non utile pour notre calcul, ou du moins négligeable.
RES est la mémoire utilisée par le processus, mais ça compte aussi la mémoire qui est potentiellement partagée.
Il ne reste que DATA, obtenu via la touche 'f' dans top. DATA, c'est la mémoire non partagée du processus, c'est donc ce qu'on cherche, dans notre cas.
Donc apache + postgresql, ça fait 9000 ko de DATA, soit à peu prés 9 mo par paire, non partagés avec les processus déjà en mémoire.
Nous pouvons donc, sur les 360 Mo, mettre 360 / 9 = 40 paires en plus, donc 40 serveurs.
La configuration d'apache devient donc :
<IfModule prefork.c> # 20 de base + les 40 plus haut # ce qui fait 60 clients MaxClient 60
# nombre maximum de processus au repos # moitié de MaxClients, mais c'est plus au feeling MaxSpareServers 30
# nombre minimum de processus au repos
MinSpareServers 5 # nombre de requêtes avant de relancer le processus MaxRequestsPerChild 1000
# nombre de serveurs lancés au démarrage StartServers 5 </IfModule>
Pourquoi ne pas avoir pris la swap en compte dans le calcul ?
En effet, il y a une partition de swap de 2 Go, et nous aurions pu la prendre en compte. Mais j'estime qu'un serveur qui commence à utiliser la swap est un serveur trop chargé. Utiliser la swap implique d'écrire sur le disque, ce qui est plus lent, ce qui ralenti les lectures ( donc le lancement d'autres processus, ou des données ), les écritures ( les logs ), et doit donc être évité en temps normal.
De plus, il existe des serveurs utilisant le disque de façon bien plus intensive que apache, et vous devez autant que possible séparer les ressources dans ce cas. Postfix et postgresql sont deux exemples de serveurs dépendants du disque, et il vaut mieux refuser une partie des clients en cas de pic, que de rendre la machine inutilisable.
Prenons un exemple : vous avez, malgré ce document, décidé de mettre plus de clients qu'il est possible de faire tenir en mémoire. Et aujourd'hui, c'est la gloire, vous passez sur cnn, pour votre papier sur les camps de tortures illégaux au sud de la floride.
Vos premiers clients arrivent, puis, le serveur commence à placer des processus dans le swap. La charge continue de monter, et le serveur devient plus lent à répondre. Les clients s'accumulent, et les processus, mettant plus de temps à traiter les requêtes, sont de moins en moins nombreux à être disponible, et apache est donc obligé de mettre les requêtes dans une file.
Le serveur, croulant sous la charge, ne répond plus au ssh, ni à la majorité des requêtes, et vous ne pouvez pas vous connecter, afin de mettre une redirection, ou de placer le document autre part. Fin de la partie. Et bien sûr, tout les autres services de la machine en pâtissent.
Avec une limitation des clients, le serveur reste en place. Vous avez tout le loisir de modifier les pages, de rediriger les autres services ailleurs, ou de libérer la mémoire des taches non essentielles ( par exemple, basculer un serveur mysql ailleurs ). Et vous continuez à servir une partie des clients web.
Copyright
© 2006 Michael Scherer
![]() ![]() ![]() |
Ce document est publié sous licence Creative Commons Attribution, Partage à l'identique 4.0 : https://creativecommons.org/licenses/by-sa/4.0/ |