Calculer l'occupation mémoire réelle d'un groupe de process?

Salut,

J’arrive pas à trouver d’infos là dessus… Je me trouve dans une situation de “faible” mémoire (768 Mo) et pour pouvoir optimiser au mieux les différents services je voudrais pouvoir calculer pour un groupe de process donné (tous le même programme) quelle est la part de mémoire propre à un process donné et quelle est la part de mémoire partagée entre tous ces process (libs communes etc), afin d’en déduire le nombre de process que je peux autoriser au total en fonction de la RAM que je veux allouer.

Plus précisément, il s’agit de calculer ça pour Apache (process forkés) d’une part et pour PHP-CGI d’autre part (chaque instance PHP est lancée indépendamment par FastCGI – je ne passe pas par le process-manager de PHP car ça provoquerait des problèmes de concurrence : FastCGI ne verrait qu’un process et n’enverrait qu’une requête à la fois, c’est pas le but).

Une piste ?

Bon du coup voici comment j’ai procédé. Je vous préviens, c’est très… euh… on va dire empirique. :mrgreen:
NB : Chaque mesure de la consommation mémoire est effectuée à l’aide de echo 3 > /proc/sys/vm/drop_caches ; free et la valeur correspond à la deuxième ligne (+/- buffers/cache).
Pour forcer plusieurs instances de PHP, j’ai lancé autant de wget que nécessaire en arrière plan via une boucle for. Typiquement : for X in 1 2 3; do { wget -O out.$X 127.0.0.1/test.php & }; done

[ul][li] faire tomber un max de services (MySQL, Dns, Cron, …) pour éviter les interférences[/li]
[li] à vide = 24472 ko[/li]
[li] apache 1 worker = 27928 ko (+3456)[/li]
[li] apache 2 workers = 28980 ko (+ 1052)[/li]
[li] apache 3 workers = 29652 ko (+672)[/li]
[li] 1 php = 33440 ko (+ 3788)[/li]
[li] 2 php = 37252 ko (+ 3812)[/li]
[li] 3 php = 40992 ko (+ 3740)[/li][/ul]

Déjà, on peut constater que les instances PHP ne partagent aucune mémoire, chaque nouvelle instance consomme autant de mémoire que la précédente. Ça m’étonne un peu mais bon y’a sûrement une explication logique (pourtant, les libs partagées devraient être communes non ? En 64 bits les binaires sont censés n’utiliser que du code position-independent donc pages mémoire communes…).
Concernant Apache, comme on pouvait s’y attendre vu qu’il s’agit de process forkés (donc en COW) la majorité du bazar est partagée.

Pour bien faire il faudrait que je pousse les mesures plus loin que 3 instances de chaque, et bien évidemment que je fasse ça dans des conditions réelles (installer les modules PHP ; une vraie page web va consommer un poil plus qu’un simple echo “hello” – mais du coup y’aura le souci de MySQL qui viendra fausser les mesures, à moins que je ne chauffe son cache d’une manière ou d’une autre pour lui faire utiliser tout ce à quoi il a le droit).
Et faudra aussi que je reconfigure mod_evasive qui grogne quand je lui balance une 10aine de requêtes simultanées. :smiley:

Sur le principe lui-même, quelqu’un a des commentaires ? Des “failles” évidentes de méthodologie que j’aurais zappé ?

Se pourrait-il que le code partagé soit compté dans le cache disque (page cache) ?
Dans l’article Wikipédia en anglais sur les fichiers mappés en mémoire http://en.wikipedia.org/wiki/Memory-mapped_file il est écrit les deux informations suivantes :

J’interprète “loadable modules” comme incluant les bibliothèques partagées.

Hmm effectivement ça pourrait y ressembler (et en plus ça se tient, quand on y pense). Dans ce cas ma méthode de mesure n’est pas bonne : si je force un drop_cache je fausse les mesures, et si je ne le fais pas c’est de toutes façons impossible de distinguer la consommation propre au programme visé avec un outil comme free. ps n’est pas d’un grand secours non plus vu qu’il ne fait pas plus la distinction.

Retour case départ donc, il faudrait trouver un outil qui soit capable de distinguer les deux types d’utilisation pour un process / groupe de process donné.

Question plus large, qui aura peut-être des réponses plus pertinentes : comment vous faites pour régler finement l’occupation mémoire maximum de l’ensemble Apache / PHP-FastCGI ? Y’a une méthode “scientifique” (et qui prenne en compte les différents modules chargés, la consommation moyenne d’une page etc) ou bien le mieux c’est de charger la bête au maximum, en augmentant les limites petit à petit jusqu’à obtention du résultat souhaité ?

Ne serait-ce pas une approche plus pragmatique de compter le cache et les buffers ? Après tout, ils ne sont pas là pour faire joli. Dans une sitation où ils seraient réduits par l’occupation mémoire des processus, les performances globales en seraient probablement affectées.

Oui, je pense que tu as raison (comme souvent :stuck_out_tongue:), ça paraît plus logique comme ça. Je ferai un test rapide demain pour voir ce que ça donne, si la première instance PHP consomme plus que les suivantes c’est probablement la bonne méthode.

Effectivement les résultats sont beaucoup plus raisonnables comme ça…
Sauf avis contraire je considère le problème comme résolu, maintenant j’ai plus qu’à faire les mesures dans des conditions réelles. Merci Pascal. :wink:

Mesure initiale :
[ul][li] echo 3 > drop_caches[/li]
[li] point [1], free (1ère ligne) : 36156[/li][/ul]

Premier round pour Apache :
[ul][li] 1 apache: 43456 (+7300 par rapport au point [1])[/li]
[li] 2 apache: 44916 (+1460)[/li]
[li] 3 apache: 45588 (+672)[/li]
[li] 4 apache: 47012 (+1424)[/li][/ul]

Deuxième round pour Apache :
[ul][li] 1 apache: 44352 (+8196 par rapport au point [1])[/li]
[li] 2 apache: 45320 (+968)[/li]
[li] 3 apache: 46352 (+1032)[/li]
[li] 4 apache: 47284 (+932)[/li][/ul]

Vérification :
[ul][li] point [2], 1 apache: 44696 (+8540 par rapport au point [1], ça semble stable)[/li][/ul]

Premier round pour PHP :
[ul][li] 1 php: 61420 (+16724 par rapport au point [2])[/li]
[li] 2 php: 64780 (+3360)[/li]
[li] 3 php: 67928 (+3148)[/li][/ul]

Deuxième round pour PHP (avec redémarrage d’Apache en passant) :
[ul][li] 1 php: 63312 (+18616 par rapport au point [2])[/li]
[li] 2 php: 67040 (+3728)[/li]
[li] 3 php: 70336 (+3296)[/li][/ul]