Dans un système d'exploitation moderne, la mémoire physique disponible peut être considérée comme un cache du disque. Toute opération sur le disque (lecture ou écriture) est conservée en mémoire, jusqu'à ce que la mémoire soit pleine. Alors une des trois options suivantes est choisie :
Le système choisit en fonction de différents paramètres (fréquence d'utilisation de la page, s'il doit faire une écrire ou non, ...).
La commande free donne une sortie du type :
total used free shared buffers cached Mem: 3986840 3104616 882224 0 547160 1415768 -/+ buffers/cache: 1141688 2845152 Swap: 1951860 35960 1915900
Comment interpréter cette sortie ?
La première ligne indique la mémoire physique totale, utilisée et libre. La mémoire utilisée est utilisée par n'importe quelle source : les binaires des programmes ou bibliothèques, la mémoire interne utilisée par le noyau, les données des programmes, le cache disque.
La deuxième ligne indique la mémoire hors cache disque et tampons (utilisés pour le réseau par exemple).
La troisième ligne indique le swap total et utilisé.
Jusque là, rien de bien sorcier. Quelques précisions, qui peuvent ne pas être évidentes au premier abord, tout de même :
La commande iostat donne des informations, de manière périodique, sur l'activité disque. Elle s'utilise par exemple avec iostat -x 5 qui donnera toutes les 5 secondes une information du type :
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util sda1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sda2 0.00 476.05 0.00 110.78 0.00 4779.24 43.14 9.99 96.76 2.80 31.06
Ainsi on peut voir sur cet exemple que sda1 n'est pas utilisé (il s'agit du swap), mais que sda2 subit des écritures de manière assez importantes, mais restant tout de même raisonnable (31% d'utilisation de la bande passante du disque).
Si jamais le taux d'utilisation dépasse les 90% alors la machine est saturée par les IO. C'est en général l'une des premières choses à regarder quand un serveur commence à ralentir : est-ce que les IOs sont saturées ?
La commande vmstat elle donne un affichage du type :
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 1 1 50820 393512 554120 2874504 0 1 556 1140 148 19 26 4 51 18
Elle permet de voir l'évolution des zones mémoires, ainsi que le nombre de pages lues depuis le swap (si), écrites sur le swap (so), autres lectures depuis le disque (bi) et autres écritures sur le disque (bo).
Si on constate une activité importante sur le disque sur un serveur qui a des problèmes de performances, il y a un grand nombre de causes possibles, qu'il faut diagnostiquer.
Si les opérations sont surtout des lectures (ou des opérations sur le swap), il peut être très intéressant d'augmenter la quantité de RAM sur la machine. Dans le cas d'une base de données, il y a une différence très importante de performances lorsque l'ensemble de la base peut tenir en RAM. Dans ce cas, il peut même être intéressant de la précharger dans le cache disque au boot, avec une commande du type :
tar cf /dev/null /var/lib/postgresql
Si les opérations sont surtout des écritures, il faut chercher si ces écritures sont normales, ou si elles peuvent être optimisées. Par exemple, une requête SQL non optimisée peut forcer la base de données à utiliser des tables temporaires sur le disque, ou des fichiers temporaires pour faire du tri. Les commandes SQL explain ou explain analyze peuvent permettre d'avoir des détails sur ce genre d'opérations. Il est aussi possible de modifier les paramètres de la base de données, pour modifier le seuil au-delà duquel les tris seront effectués sur le disque et non en mémoire.
La première commande à exécuter quand un serveur semble ramer est la commande uptime, qui va donner le load average. Il s'agit de la moyenne du nombre de processus en attente de ressources (accès au CPU ou au disque) pendant une période de temps (trois valeurs, pour 1 minute, 5 minutes, 15 minutes).
Deux informations sont importantes :
La seconde commande pour analyser l'utilisation CPU est la commande 'top'. Elle indique la liste des processus, classés par l'utilisation CPU qu'ils font, ainsi que l'état total des différents coeurs.
L'état total des CPUs est réparti entre :
Note : attention à la commande top, elle est modérément gourmande en ressources, et peut aggraver la situation sur un serveur déjà très chargé.
Un point important est à considérer pour les deux commandes précédentes : le traitement du multicoeur (ou du multicpu, ce qui revient au même).
Lorsque top liste les temps globaux, il s'agit d'une moyenne sur tous les CPUs : ainsi, si on a 2 coeurs, et que top indique 50% de userspace et 50% de idle, il s'agit probablement d'un coeur fonctionnant à fond, tandis qu'un autre coeur n'est pas utilisé.
En effet, un même programme ne peut pas s'exécuter sur deux CPU à la fois, à l'exception des programmes multithreadés. Et encore, pour ceux-là, il faut qu'il n'y ait pas de lock, comme le Global Interpreter Lock de Python (donc, un programme Python, même multithreadé, ne s'exécutera que sur un seul coeur).
Ajouter des coeurs ne sert à rien si les services ne sont pas suffisamment parallélisés.
Si le système semble au repos, mais que l'application met du temps à répondre, il faut se demander si l'application n'est pas bloquée par quelque chose d'externe, en général un service réseau qui mettrait du temps à répondre.
Pour cela deux commandes sont indispensables :
Un autre outil extrêmement pratique pour analyser les raisons de la lenteur d'un Zope (ici, il s'agit d'un produit Zope, mais le concept peut être reproduit sur d'autres frameworks Web) : le DeadlockDebugger (http://plone.org/products/deadlockdebugger/ ).
Ce produit permet d'avoir, en temps réel, l'état (la pile d'exécution) de tous les threads d'un Zope, et donc de voir dans quelle partie du code il est "coincé".
Attention cependant : en raison du mode de fonctionnement de l'ordonnancement des threads Python, le DeadlockDebugguer prendra quasiment toujours la main lors d'un appel système. Les dernières lignes de la pile seront très souvent un lseek ou un read, mais ce n'est pas pourtant que ce sont réellement ces appels qui prennent le plus de temps. Il vaut mieux remonter quelques niveau de plus de la pile, et voir à un niveau applicatif quel est le code concerné (recherche catalogue, rendu d'un template, ...).
Cet article liste quelques outils, la manière d'interpréter leurs résultats, et des actions à mener pour résoudre un problème du type "mon service rame". Cependant, il faut bien se souvenir que rien ne remplacera un travail d'investigation, une analyse du code et des requêtes SQL s'il y en a, ...
Actions sur le document