La question est presque toujours la même : cette nuit, le site mettait vingt secondes à répondre, et au matin tout était rentré dans l’ordre tout seul. Il n’y a plus rien à regarder — top répond pour la seconde en cours, alors que la question porte sur trois heures du matin. Voici ce que signifient réellement les chiffres de la charge, lesquels doivent se lire par paires, et pourquoi une mesure isolée induit en erreur plus souvent qu’elle n’aide.
Load average : trois nombres et un contresens fréquent
uptime
cat /proc/loadavg
nproc
Ces trois nombres sont des moyennes sur une, cinq et quinze minutes. Ils ne se comparent pas à zéro mais au nombre de cœurs que donne nproc. Une valeur de 8 sur une machine à huit cœurs, c’est une charge pleine mais saine : il y a exactement autant de travail que le serveur peut en abattre. Une valeur de 2 sur un VPS à un cœur, c’est une file d’attente deux fois plus longue que la capacité, et chaque requête attend son tour.
Le rapport entre les trois nombres donne la direction. Le chiffre à une minute nettement au-dessus de celui à quinze minutes signifie que la charge monte en ce moment même. L’inverse signifie que le pic est passé et que vous en regardez la queue.
Vient maintenant le contresens qui fausse ces chiffres plus que tout le reste. Sous Linux, le load average n’est pas « l’utilisation du processeur ». Contrairement à d’autres systèmes Unix, Linux y compte non seulement les processus qui s’exécutent ou sont prêts à le faire, mais aussi ceux qui sont dans l’état D — le sommeil ininterruptible. C’est-à-dire l’attente du disque ou d’un système de fichiers réseau. D’où le serveur affichant un load de 12 avec un processeur presque inoccupé : le travail n’avance pas, tout le monde fait la queue.
Processeur ou disque
Séparer ces deux cas est la première chose à faire :
vmstat 1 5
iostat -x 1 3
Dans la sortie de vmstat, trois colonnes comptent. r indique combien de processus attendent le processeur, b combien sont bloqués en attente d’entrées-sorties, et wa la part du temps que le processeur a passée inoccupé à attendre le disque. Un wa durablement au-dessus de 10–15 % avec des us et sy modestes signifie que le serveur bute sur le disque : ajouter des cœurs ne sert à rien, ceux dont vous disposez sont déjà libres.
Les processus qui attendent se listent nommément :
ps -eo state,pid,comm,wchan:30 | awk '$1 ~ /^D/'
Un exemple tiré de notre propre pratique. Avec sa configuration par défaut, Suricata écrit une trentaine de types d’événements et ne met en place aucune rotation — sur un serveur en production, cela a donné 15 Go de journaux en deux jours. La charge ne se manifestait pas par un processeur occupé mais précisément par de l’I/O wait : le système écrivait sans interruption et tout le reste faisait la queue derrière lui. Le remède n’est pas une offre plus grosse, mais une liste d’événements plus courte et une rotation configurée.
Le cas inverse, purement processeur et bien moins évident. Une page web appelait apt sous l’utilisateur qui fait tourner PHP-FPM. Root conserve un cache binaire dans /var/cache/apt/pkgcache.bin — 70 Mo sur un hôte doté d’une douzaine de dépôts — et le projette en mémoire gratuitement. Un utilisateur ordinaire ne peut pas écrire dans ce répertoire et reconstruit ce cache à chaque appel. Mesuré sur une seule et même machine : 0,01 seconde de temps processeur en root contre 4,2 secondes en utilisateur non privilégié. La même commande, un facteur quatre cents, multiplié par chaque affichage de page.
La conclusion des deux cas est la même : la charge se mesure, elle ne se devine pas. Chronométrer séparément chaque commande suspecte prend une demi-heure et désigne d’ordinaire autre chose que ce que l’on soupçonnait au départ.
La mémoire : free ne montre pas ce qu’on croit
free -h
La colonne used prise isolément dit très peu de chose, et la colonne free est franchement trompeuse : Linux confie la mémoire inutilisée au cache de pages et la rend aux applications à la première demande. La colonne à lire est available — ce qui peut être occupé sans partir en swap. Un buff/cache important n’est pas un problème mais le signe d’un système qui fonctionne comme prévu.
Pour le swap, ce qui compte n’est pas la valeur du moment mais la forme. Monté puis revenu à zéro : il y a eu un pic bref. Monté une fois et resté là : le pic a déjà eu lieu, des pages ont été évincées et personne ne les remonte — le serveur paraît calme alors qu’à un moment la mémoire lui a manqué. Pour savoir si l’échange a lieu en ce moment, il y a les colonnes si et so de vmstat ; des valeurs non nulles y sont la forme de ralentissement que les utilisateurs remarquent le plus.
Si un processus a tout simplement disparu pendant le creux nocturne, l’explication est généralement ici :
journalctl -k --since yesterday | grep -i "out of memory"
dmesg -T | grep -i "killed process"
Une ligne du type Out of memory: Killed process 1234 (mysqld) tranche mieux que n’importe quel graphique : la base de données n’est pas « tombée toute seule », c’est le noyau qui l’a arrêtée, faute de mémoire.
Qui en est responsable
ps aux --sort=-%cpu | head -10
ps aux --sort=-%mem | head -10
Une réserve : le %CPU de ps est une moyenne sur toute la vie du processus, si bien qu’une flambée courte se perd dans cette liste. Pour celle-ci il faut top ou pidstat 1 5, qui mesurent sur un intervalle.
Quand la charge devient une question de sécurité
Un processeur à 100 % de façon plate pendant la nuit, avec un processus au nom sans signification et au répertoire de travail dans /tmp ou /dev/shm, c’est l’image classique d’un mineur, pas celle d’un site qui a grandi. Une pointe de trafic entrant accompagnée d’une hausse des écritures dans les journaux, c’est une attaque de mots de passe en cours. Un volume de journaux qui bondit brusquement, c’est en général une tempête de faux positifs d’un filtre.
Les outils de protection eux-mêmes forment une catégorie à part. Sur l’un de nos serveurs, le load se tenait autour de trois sans le moindre visiteur, et en tête de ps par temps processeur cumulé figuraient non pas le site ni la base, mais CrowdSec, fail2ban, Falco et Suricata. Ce n’est ni une panne ni une raison de les désactiver, mais il est utile de connaître le prix de la protection en chiffres : sur un petit VPS, il se voit.
L’intérêt de l’observation
Tout ce qui précède répond à la question « que se passe-t-il maintenant ». La question du matin — que s’est-il passé à trois heures — n’est pas couverte par ces commandes : il n’existe aucune donnée sur la nuit écoulée si rien ne l’a enregistrée. Et monter Prometheus et Grafana pour un seul VPS est discutable, la pile d’observation finissant plus lourde que le serveur observé.
Une ligne en base toutes les cinq minutes et une page qui en trace les dernières 24 heures suffisent : load average, utilisation du processeur et I/O wait séparément, mémoire et swap, lectures et écritures disque, remplissage de la partition, inodes, descripteurs de fichiers, connexions. Sur un même axe de temps, les paires se lisent à l’œil : un wa élevé avec un processeur tranquille, un swap qui n’est jamais revenu à zéro, des descripteurs qui approchent de la limite — la future erreur too many open files devient visible des heures avant de survenir. À quoi cela ressemble une fois assemblé : voir la page de démonstration ci-dessous.