Métriques d'une VM: CPU, charge, RAM, swap...

Publié le · Mis à jour le

L'idée en une phrase

Les graphiques d'une machine (CPU, RAM, charge, swap, disque) racontent ce que vit ton application. Une métrique seule dit peu de choses ; c'est en les lisant ensemble qu'on comprend si l'application calcule trop, attend quelque chose ou manque de mémoire.

Une image pour comprendre : le bilan médical

Un médecin ne pose pas un diagnostic sur la seule température. Fièvre + toux, ce n'est pas la même chose que fièvre + mal de ventre. Il croise les mesures, et il les compare à ce qui est normal pour ce patient.

Avec une machine, c'est pareil :

  • un CPU à 90 % n'est pas forcément un problème ;
  • un CPU à 90 % et des temps de réponse qui explosent depuis le déploiement de ce matin, ça raconte une histoire.

Garde ce réflexe pour toute la fiche : combiner les métriques et comparer avec la normale.

D'où viennent les graphiques ?

Dans un projet classique, deux sources alimentent les tableaux de bord (souvent dans Grafana, avec Prometheus qui collecte les mesures) :

Source Ce qu'elle mesure Exemples
La machine (via un agent comme node_exporter) ce que voit le système CPU, RAM, charge, swap, disque, réseau
L'application Spring Boot (via Actuator et Micrometer) ce que vit Java à l'intérieur heap, GC, temps de réponse HTTP, connexions à la base

Les deux sont indispensables. La machine dit que quelque chose se passe ; l'application aide à dire quoi.

Les métriques une par une

Le CPU

Le pourcentage de temps où le processeur travaille. Le total se découpe en plusieurs parts, et c'est ce découpage qui est intéressant :

Part Signification Si elle est élevée…
user le processeur exécute des programmes (ton application) l'application calcule beaucoup
system le processeur exécute le système (réseau, fichiers…) beaucoup d'échanges avec le système
iowait le processeur attend le disque le disque est trop lent ou trop sollicité
steal la VM attend que l'hébergeur lui donne du CPU la machine physique est surchargée par d'autres VM
idle le processeur ne fait rien tout va bien de ce côté

Note : steal n'existe que sur une machine virtuelle. S'il monte, le problème n'est pas dans ton code : la machine physique qui héberge ta VM est partagée et saturée. C'est un sujet pour l'hébergeur.

La charge (load average)

C'est le nombre de tâches qui veulent travailler : celles qui utilisent un cœur, celles qui attendent leur tour, et (sous Linux) celles qui attendent le disque.

On la lit en trois valeurs : moyenne sur 1, 5 et 15 minutes. Par exemple 2.10 1.80 0.90 : la charge monte (elle est plus forte sur la dernière minute que sur le dernier quart d'heure).

Pour l'interpréter, compare-la au nombre de cœurs :

Machine à 4 cœurs Lecture
charge à 2 les cœurs ne sont pas tous occupés : confortable
charge à 4 les cœurs sont pleinement utilisés
charge à 12 trois fois plus de tâches que de cœurs : des tâches font la queue

Astuce : une charge élevée avec un CPU bas, c'est le signe que les tâches attendent le disque, pas le processeur. Regarde alors iowait.

La RAM

C'est le piège le plus courant pour un débutant : une RAM « pleine » n'est pas forcément un problème.

Linux utilise la mémoire libre pour garder en cache les fichiers lus récemment. Ça accélère tout, et il la rend dès qu'un programme en a besoin. Une machine saine affiche donc souvent une mémoire « utilisée » élevée.

La bonne métrique est la mémoire disponible (available) : ce qui peut réellement être donné à un programme, cache compris.

Métrique À regarder ?
mémoire utilisée (used) trompeuse : elle compte le cache
mémoire disponible (available) ✅ c'est elle qui compte

Une particularité de Java : au démarrage, la JVM réserve de la mémoire pour sa heap et la rend rarement au système, même quand la heap se vide. Vue de la machine, la RAM de l'application reste donc haute et plate. C'est normal. Pour savoir ce qui se passe vraiment, il faut regarder la heap côté application (voir plus bas).

Le swap

Le swap est un espace sur le disque que le système utilise quand il n'a plus assez de RAM. Le disque étant des milliers de fois plus lent que la RAM, tout ralentit.

Deux mesures à ne pas confondre :

Mesure Lecture
swap occupé un peu de swap occupé peut être ancien et sans conséquence
activité de swap (pages écrites et relues en continu) 🚨 la machine manque de RAM maintenant

Java supporte très mal le swap : le garbage collector parcourt toute la heap, et si une partie est sur le disque, chaque nettoyage devient interminable. L'application se fige par moments, sans erreur.

Le disque

Deux choses à surveiller :

  • l'espace libre : un disque plein fait planter l'application ou la base de données. La cause la plus fréquente : des logs qui grossissent sans être archivés ni supprimés.
  • l'occupation (le disque est-il occupé en permanence ?) : elle se voit aussi dans iowait.

Les métriques de l'application

Une application Spring Boot avec Actuator expose ses propres mesures. Les plus parlantes :

Métrique Ce qu'elle montre
heap utilisée la mémoire occupée par les objets Java
pauses du GC le temps passé par Java à faire le ménage
temps de réponse HTTP ce que ressentent les utilisateurs
connexions à la base actives / en attente si le pool de connexions est saturé

Lire les métriques ensemble : les cas typiques

C'est le cœur de la fiche. Chaque cas part d'un symptôme, croise plusieurs graphiques, et en tire une explication.

1. Le CPU est à 100 % en user

Ce que tu vois : CPU très haut, charge élevée, application lente.

Ce que ça révèle : l'application calcule énormément. Deux pistes :

  • un traitement lourd (une boucle sur une grosse liste, un export, un calcul) ;
  • le garbage collector qui tourne sans arrêt parce que la heap est presque pleine.

Pour trancher : regarde la heap et les pauses du GC. Si la heap est au plafond et que le GC est très actif, le CPU n'est que la conséquence : le vrai problème est la mémoire (voir la fiche sur la mémoire en Java).

2. Le CPU est bas, mais l'application est lente

Ce que tu vois : CPU calme, charge normale, mais des temps de réponse élevés.

Ce que ça révèle : l'application attend quelque chose : la base de données, une API externe, ou une connexion libre dans le pool.

Pour trancher : regarde les connexions à la base. Si des requêtes sont en attente d'une connexion, le pool est saturé (souvent à cause de requêtes SQL lentes qui gardent leur connexion trop longtemps). Sinon, regarde les temps de réponse des services appelés. La machine n'y est pour rien : elle se tourne les pouces.

3. La charge est haute, le CPU est bas, iowait monte

Ce que tu vois : une charge à 10 sur une machine à 4 cœurs, mais un CPU à 20 %.

Ce que ça révèle : les tâches font la queue pour le disque. Causes fréquentes : beaucoup de logs écrits (un niveau DEBUG oublié en production), une base de données sur la même machine qui lit beaucoup, ou… du swap (cas suivant).

4. La RAM disponible baisse et le swap s'active

Ce que tu vois : mémoire disponible proche de zéro, activité de swap, iowait qui grimpe, application qui se fige par moments.

Ce que ça révèle : la machine n'a plus assez de RAM pour tout ce qui tourne dessus. Souvent : trop de programmes sur la même VM, ou une heap Java réglée plus grande que ce que la machine peut offrir.

Ce qui arrive ensuite : si rien ne change, Linux finit par tuer un programme pour récupérer de la mémoire (l'OOM killer). Souvent, c'est le plus gros… donc ton application Java.

Note : ne confonds pas les deux « out of memory ». Un OutOfMemoryError de Java laisse une erreur dans les logs de l'application. Quand c'est Linux qui tue le processus, l'application disparaît sans aucune erreur Java : la trace se trouve dans les logs du système.

5. La heap remonte un peu plus haut après chaque nettoyage

Ce que tu vois : sur le graphique de la heap, une courbe en dents de scie (elle monte, le GC passe, elle redescend)… mais le bas des dents remonte jour après jour.

Ce que ça révèle : une fuite mémoire. Des objets restent désignés et le GC ne peut plus les supprimer. Le plantage n'est qu'une question de temps.

Normal :              Fuite :
 /\  /\  /\  /\                    /\/\
/  \/  \/  \/  \             /\/\/
                        /\/\/
                   /\/\/

Des dents de scie au même niveau, c'est sain : c'est le GC qui fait son travail.

6. steal monte, sans raison côté application

Ce que tu vois : application lente, CPU apparemment occupé, mais une part importante en steal.

Ce que ça révèle : la machine physique de l'hébergeur est saturée par d'autres VM. Ton code n'y est pour rien et aucune modification n'y changera quoi que ce soit : c'est à remonter à l'équipe qui gère l'hébergement.

7. L'espace disque baisse régulièrement

Ce que tu vois : une courbe d'espace libre qui descend en ligne droite, jour après jour.

Ce que ça révèle : quelque chose écrit sans jamais nettoyer, le plus souvent des fichiers de logs. Prolonge la ligne : tu sais quand le disque sera plein.

Le tableau récapitulatif

CPU Charge RAM disponible Swap Piste principale
haut (user) haute normale non calcul lourd, ou GC qui s'emballe
bas normale normale non l'application attend (base, API, pool)
bas (iowait haut) haute normale non disque saturé (logs, base de données)
variable (iowait haut) haute basse oui manque de RAM sur la machine
haut (steal) variable normale non hébergeur saturé

Si tu as accès à la machine

Quelques commandes Linux pour vérifier par toi-même. Elles ne modifient rien :

uptime      # la charge sur 1, 5 et 15 minutes
nproc       # le nombre de cœurs, pour comparer avec la charge
free -h     # la RAM : regarde la colonne "available"
top         # les programmes qui consomment le plus ; la ligne %Cpu montre us, sy, wa (iowait), st (steal)
vmstat 1    # une ligne par seconde ; colonnes si/so différentes de 0 = activité de swap
df -h       # l'espace libre sur chaque disque

Les bonnes habitudes

  1. Connais la normale. Regarde les tableaux de bord quand tout va bien : c'est ce qui te permettra de repérer ce qui est anormal.
  2. Ne conclus jamais sur une seule métrique. Croise au moins le CPU, la charge, la mémoire et les temps de réponse.
  3. Regarde la RAM disponible, pas la RAM utilisée.
  4. Regarde l'activité du swap, pas seulement le swap occupé.
  5. Pour la mémoire d'une application Java, regarde la heap, pas la RAM de la machine.
  6. Situe le problème dans le temps. Un déploiement, un traitement planifié, une heure de pointe ? La plupart des incidents s'expliquent par « qu'est-ce qui a changé à ce moment-là ».
  7. Décris ce que tu vois avant de proposer une solution. « La charge est à 10 sur 4 cœurs avec 40 % d'iowait depuis 14 h » aide toute l'équipe ; « le serveur rame » n'aide personne.

À retenir

  • Une métrique seule ne dit presque rien : c'est la combinaison qui révèle ce qui se passe.
  • CPU haut : l'application calcule (ou le GC s'emballe). CPU bas mais lenteur : l'application attend quelque chose.
  • La charge se compare au nombre de cœurs ; haute avec un CPU bas, elle pointe vers le disque.
  • Une RAM « pleine » est normale sous Linux et avec Java ; le vrai signal d'alarme, c'est le swap actif.
  • Une heap dont le niveau bas remonte jour après jour signale une fuite mémoire.
  • steal élevé : le problème est chez l'hébergeur, pas dans ton code.

Avis sur l'article

Pas encore de note : soyez le premier à donner votre avis.

Les avis sont publiés après validation par le modérateur.

Votre note