Ça commence par « la VM semble lente ». Dix minutes plus tard on se retrouve avec « pourquoi kswapd bouffe un cœur », et une heure après quelqu’un propose « ajoutez du swap » comme s’il aspergeait du saint‑huile sur un feu.
Ubuntu 24.04 peut très bien tourner de manière stable sous pression mémoire. Mais si vous mélangez ballooning, overcommit, limites cgroup et des valeurs par défaut trop optimistes, vous pouvez fabriquer une swap storm qui ressemble à la fois à un problème CPU, disque et réseau. Ce n’est pas de la magie. C’est de la comptabilité, et ça se corrige.
Ce que signifie réellement “ballooning mémoire surprises”
Le ballooning est simple en théorie : l’hyperviseur reprend de la RAM à une VM qui « ne l’utilise pas », et la donne à autre chose. En pratique, c’est une négociation avec une information imparfaite.
À l’intérieur du guest (Ubuntu 24.04 ici), le pilote balloon fixe des pages pour que le guest pense qu’il a moins de mémoire utilisable. Si le guest a ensuite besoin de cette mémoire, l’hyperviseur peut « dégonfler » le ballon — si il le peut. Ce « si » est l’endroit où naissent les indisponibilités.
Une swap storm, c’est ce qui arrive quand un système passe plus de temps à déplacer des pages entre RAM et swap qu’à faire du travail utile. Le schéma classique :
- La pression mémoire augmente → les pages anonymes sont swapées
- La charge touche des pages swapées → les défauts majeurs explosent
- Les waits d’IO augmentent → les latences des requêtes grimpent
- Le CPU est consommé par le reclaim et les page faults → la machine « a du CPU » mais rien ne se termine
Ajoutez maintenant les surprises du ballooning :
- L’« available » du guest chute rapidement (le ballon se gonfle), parfois plus vite que le guest ne peut récupérer proprement.
- Le guest commence à swapper même si l’hôte a encore de la mémoire au global — ou bien l’hôte est aussi sous pression, et les deux couches font du reclaim simultanément.
- Les métriques semblent contradictoires : le guest montre du swap ; l’hôte affiche de la mémoire libre ; les latences applicatives ressemblent à un problème disque ; et le CPU est occupé mais improductif.
La partie opinionnée : si vous avez besoin de prévisibilité, arrêtez de traiter la mémoire comme une suggestion flottante. Mettez des limites dures là où il le faut, dimensionnez le swap volontairement, et choisissez une couche qui fait le reclaim en premier. Sinon vous gérez un système de pagination distribué, et personne n’a demandé ça.
Blague n°1 (courte, pertinente) : Le swap, c’est comme mettre des cartons dans un garde‑meubles pendant un déménagement — utile jusqu’au moment où vous avez besoin du grille‑pain tout de suite.
Faits intéressants et contexte historique (court, utile, un peu nerd)
- Le ballooning est antérieur au « cloud ». VMware a popularisé le ballooning au début des années 2000 pour améliorer les ratios de consolidation — jusqu’à ce que les charges deviennent pleines de pics et sensibles à la latence.
- virtio-balloon est coopératif. Il repose sur le guest pour rendre des pages. Si le guest est déjà en difficulté, le ballooning peut amplifier la douleur parce que le guest fait le travail de reclaim.
- Le swapping Linux n’est pas « un bug ». Historiquement, Linux utilisait le swap de manière proactive pour augmenter le cache de pages ; les noyaux modernes sont plus nuancés, mais de l’activité de swap seule n’est pas une condamnation.
- cgroup v2 a rendu le contrôle mémoire plus strict et plus observable. Il est plus difficile de contourner accidentellement les limites, et plus simple de voir la pression et les événements — à condition de regarder.
- PSI (Pressure Stall Information) est assez récent. Il a été intégré autour du noyau Linux 4.20 pour quantifier le « temps passé à attendre les ressources », rendant mesurable le « la machine semble lente ».
- systemd-oomd est un tueur utilisateur opinionné. Il peut agir plus tôt que le kernel OOM killer pour préserver le système, ce qui surprend ceux qui pensent que OOM veut dire « seulement quand tout est épuisé ».
- Les valeurs par défaut d’overcommit varient selon l’environnement. Les hyperviseurs sur‑engagent ; Linux peut sur‑engager ; les conteneurs peuvent sur‑engager. Superposez tout cela et vous avez une poupée russe d’optimisme.
- Les swap storms ont empiré avec les disques rapides. NVMe rend le swap « moins horrible », ce qui pousse à s’y appuyer ; cela déplace souvent le goulot d’étranglement vers le CPU et la variance de latence.
Playbook de diagnostic rapide : trouver le goulot en minutes
C’est l’ordre qui gagne en production parce qu’il sépare « nous sommes sous pression mémoire » de « nous sommes confus ». Faites‑le d’abord sur le guest, puis sur l’hôte si vous le pouvez.
1) Confirmer que c’est une pression mémoire, pas juste une « utilisation RAM élevée »
- Vérifiez le taux de swap-in et les majors faults (vraie douleur).
- Vérifiez le PSI mémoire (temps passé bloqué).
- Vérifiez le CPU de reclaim (
kswapdet reclaim direct).
2) Identifier où le reclaim se produit (guest ? hôte ? les deux ?)
- Dans le guest, confirmez le statut du pilote balloon et la taille actuelle du ballon si exposée.
- Sur l’hôte, vérifiez la cible du ballon de la VM et l’activité de swap de l’hôte.
3) Déterminer quel plan de contrôle applique réellement les limites
- cgroup v2 memory.max / memory.high pour services et conteneurs
- activité et logs de systemd-oomd
- limites mémoire / politique de ballooning de l’hyperviseur
4) Décider de la mitigation immédiate
- Si la latence est en feu : réduisez la cible de ballooning ou ajoutez de la RAM réelle (n’ajoutez pas seulement du swap).
- Si un service est gourmand : limitez‑le via cgroups, ou relancez‑le avec un heap / nombre de workers réduit.
- Si l’hôte est sous pression : arrêtez l’overcommit, migrez ou diminuez la charge — le swap de l’hôte rend chaque invité triste.
Tâches pratiques : commandes, sorties et décisions (12+)
Ce ne sont pas des commandes « lancez et vous vous sentez bien ». Chacune a une interprétation et une décision associée. Utilisez‑les pendant un incident et de nouveau en postmortem.
Task 1: Check memory and swap totals quickly
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 15Gi 13Gi 210Mi 220Mi 1.8Gi 820Mi
Swap: 8.0Gi 6.4Gi 1.6Gi
Ce que cela signifie : « available » < 1 GiB plus un usage swap important suggèrent une pression active, pas juste de la mémoire cache.
Décision : Si la latence est élevée et que le swap utilisé augmente, passez immédiatement aux Tâches 2–4. Si le swap est élevé mais stable et que PSI est bas, ça peut aller.
Task 2: Measure swap-in/out and reclaim churn
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
3 1 671088 180000 12000 860000 420 980 1800 2100 3200 8800 18 12 10 58 2
2 1 672000 175000 12000 850000 300 760 1400 1800 3100 8200 16 11 12 59 2
4 2 675000 165000 11000 845000 520 1200 2200 2400 3500 9300 20 14 8 56 2
2 1 677000 160000 11000 840000 410 900 1700 2000 3200 8600 18 12 10 58 2
3 2 679000 155000 10000 835000 600 1300 2400 2600 3600 9700 21 15 7 55 2
Ce que cela signifie : si/so non nuls en continu indiquent un swap actif. Un wa élevé signifie que l’IO wait domine. C’est le profil d’une swap storm.
Décision : Atténuez en réduisant la pression mémoire (plus de RAM / moins de ballooning / limiter les coupables). Tuner swappiness ne vous sauvera pas en plein orage.
Task 3: Look for major page faults (the “I touched swapped pages” counter)
cr0x@server:~$ sar -B 1 3
Linux 6.8.0-xx-generic (server) 12/31/25 _x86_64_ (8 CPU)
12:01:11 AM pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff
12:01:12 AM 1800.00 2400.00 52000.00 980.00 14000.00 9200.00 0.00 6100.00 66.30
12:01:13 AM 1600.00 2100.00 50500.00 1020.00 13200.00 8900.00 0.00 5800.00 65.10
12:01:14 AM 2000.00 2600.00 54000.00 1100.00 15000.00 9800.00 0.00 6400.00 65.30
Ce que cela signifie : majflt/s proche de 1000 est brutal pour la plupart des services. Chaque major fault signifie « attente disque ».
Décision : Arrêtez l’hémorragie : réduisez le ballooning, tuez/restart le gourmant mémoire, ou scalez horizontalement. Si vous ne faites rien, vous aurez des timeouts et des retries en cascade.
Task 4: Read PSI memory pressure (guest-side truth serum)
cr0x@server:~$ cat /proc/pressure/memory
some avg10=35.20 avg60=22.10 avg300=10.88 total=987654321
full avg10=12.90 avg60=7.40 avg300=3.20 total=123456789
Ce que cela signifie : « some » = tâches ralenties à cause de la pression mémoire ; « full » = personne ne peut fonctionner parce que la mémoire est le goulot. Un « full » soutenu non négligeable est une alerte rouge.
Décision : Si full avg10 dépasse ~1–2% pour des systèmes sensibles à la latence, considérez‑le comme un incident de production. Réduisez la pression ; ne discutez pas les chiffres.
Task 5: See if kswapd is burning CPU
cr0x@server:~$ top -b -n1 | head -n 15
top - 00:01:40 up 12 days, 3:22, 1 user, load average: 8.22, 7.90, 6.40
Tasks: 243 total, 4 running, 239 sleeping, 0 stopped, 0 zombie
%Cpu(s): 21.3 us, 14.9 sy, 0.0 ni, 6.8 id, 56.0 wa, 0.0 hi, 1.0 si, 0.0 st
MiB Mem : 16384.0 total, 15870.0 used, 220.0 free, 180.0 buff/cache
MiB Swap: 8192.0 total, 6600.0 used, 1592.0 free. 820.0 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
431 root 20 0 0 0 0 R 85.0 0.0 120:22.11 kswapd0
2331 app 20 0 5020.0m 3900.0m 4200 S 60.0 23.8 88:10.22 java
1102 postgres 20 0 2800.0m 1500.0m 9800 S 25.0 9.2 40:11.03 postgres
Ce que cela signifie : IO wait élevé plus kswapd0 chaud signifie que le reclaim thrash. Le CPU est « occupé » à faire des tâches ménagères.
Décision : N’optimisez pas encore l’application. Réglez la pression mémoire d’abord ; sinon vous peaufinez la playlist d’un navire qui coule.
Task 6: Inspect what the kernel thinks about memory and reclaim
cr0x@server:~$ egrep 'MemTotal|MemAvailable|SwapTotal|SwapFree|Active|Inactive|Dirty|Writeback|AnonPages|Mapped|SReclaimable' /proc/meminfo
MemTotal: 16384000 kB
MemAvailable: 780000 kB
SwapTotal: 8388604 kB
SwapFree: 1654320 kB
Active: 8920000 kB
Inactive: 5120000 kB
Dirty: 184000 kB
Writeback: 2400 kB
AnonPages: 11200000 kB
Mapped: 420000 kB
SReclaimable: 520000 kB
Ce que cela signifie : De grandes AnonPages indiquent de la mémoire anonyme (heaps, pas cache). C’est là que vient la pression sur le swap.
Décision : Si c’est majoritairement anonyme, il vous faut moins de processus, des heaps plus petits, ou plus de RAM. Si c’est principalement du cache, vous pouvez récupérer proprement.
Task 7: Find top memory consumers (RSS, not VIRT)
cr0x@server:~$ ps -eo pid,comm,rss,pmem --sort=-rss | head
2331 java 3998200 24.3
1102 postgres 1543000 9.4
4120 node 1022000 6.2
1887 redis-server 620000 3.8
2750 python 410000 2.5
987 systemd-journald 180000 1.1
1450 nginx 90000 0.5
812 snapd 82000 0.5
701 multipathd 62000 0.3
655 unattended-upgr 52000 0.3
Ce que cela signifie : RSS est la mémoire résidente réelle. Un seul gros processus peut déstabiliser tout le guest une fois que le ballooning réduit la marge.
Décision : Si un processus domine, limitez‑le (cgroup), reconfigurez‑le, ou relancez‑le volontairement — avant que le système ne le fasse pour vous.
Task 8: Check cgroup v2 memory limits for a systemd service
cr0x@server:~$ systemctl show myapp.service -p MemoryMax -p MemoryHigh -p OOMPolicy -p ManagedOOMMemoryPressure
MemoryMax=infinity
MemoryHigh=infinity
OOMPolicy=stop
ManagedOOMMemoryPressure=auto
Ce que cela signifie : Pas de plafonds mémoire. L’app peut manger le guest. Avec le ballooning, cela devient de la roulette russe.
Décision : Pour des hôtes critiques, définissez MemoryHigh (throttle soft) et MemoryMax (plafond dur) pour imposer de la prévisibilité.
Task 9: Inspect the cgroup’s actual memory current and events
cr0x@server:~$ CG=$(systemctl show -p ControlGroup --value myapp.service); echo $CG
/system.slice/myapp.service
cr0x@server:~$ cat /sys/fs/cgroup$CG/memory.current
4219031552
cr0x@server:~$ cat /sys/fs/cgroup$CG/memory.events
low 0
high 182
max 3
oom 1
oom_kill 1
Ce que cela signifie : Le service a atteint memory.high souvent et a même touché memory.max. Il y a eu un OOM kill dans le cgroup.
Décision : Si high augmente rapidement, ajustez le service (heap/workers) ou augmentez les limites. Si max/oom_kill augmente, vous êtes sous‑dimensionné ou mal configuré.
Task 10: See swap usage per process (smaps rollup)
cr0x@server:~$ sudo awk '/^Swap:/ {sum+=$2} END {print sum " kB"}' /proc/2331/smaps_rollup
1540000 kB
Ce que cela signifie : Ce processus a ~1.5 GiB swapés. Même s’il « tourne encore », il est probablement en pause dès qu’il touche des régions swapées.
Décision : Si c’est un service sensible à la latence, le redémarrage (après réduction de l’empreinte mémoire) peut être la moins mauvaise option. Corrigez aussi la cause en amont (ballooning/limites).
Task 11: Check kernel swappiness and reclaim knobs
cr0x@server:~$ sysctl vm.swappiness vm.vfs_cache_pressure vm.watermark_scale_factor
vm.swappiness = 60
vm.vfs_cache_pressure = 100
vm.watermark_scale_factor = 10
Ce que cela signifie : Swappiness 60 est la valeur par défaut générique. Ce n’est pas « faux », mais ce n’est pas taillé pour des VMs balloonées exécutant des apps sensibles à la latence.
Décision : Après l’incident, envisagez vm.swappiness=10–30 pour beaucoup de serveurs, mais seulement après avoir résolu le dimensionnement et les limites.
Task 12: Confirm which swap devices are active and their priority
cr0x@server:~$ swapon --show --bytes
NAME TYPE SIZE USED PRIO
/swapfile file 8589934592 7088373760 -2
Ce que cela signifie : Swapfile unique, priorité basse (normale). Si vous avez plusieurs backends de swap, les priorités décident où les pages vont en premier.
Décision : Si vous introduisez zram, donnez‑l une priorité supérieure au swap disque pour compresser avant de toucher la latence IO.
Task 13: Observe disk latency during swapping
cr0x@server:~$ iostat -x 1 3
Linux 6.8.0-xx-generic (server) 12/31/25 _x86_64_ (8 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
18.20 0.00 12.10 56.30 2.10 11.30
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
nvme0n1 420.0 16800.0 2.0 0.47 9.80 40.0 520.0 22000.0 3.0 0.57 18.50 42.3 12.10 98.00
Ce que cela signifie : %util ~98% et des awaits élevés signifient que le disque est saturé. Sous swap, même un NVMe peut devenir le goulot.
Décision : Si le swap est la charge, ajouter un « disque plus rapide » ne réparera pas le problème. Réduisez d’abord le swap.
Task 14: Check for host-side memory ballooning from within the guest (driver presence)
cr0x@server:~$ lsmod | grep -E 'virtio_balloon|vmw_balloon|xen_balloon'
virtio_balloon 24576 0
virtio 16384 2 virtio_balloon,virtio_net
Ce que cela signifie : Le pilote virtio balloon est chargé, donc le ballooning peut être actif selon la politique de l’hyperviseur.
Décision : Si vous ne tolérez pas la mémoire dynamique, coordonnez‑vous avec l’équipe hyperviseur pour désactiver ou contraindre le ballooning pour cette classe de VM.
Task 15: See recent OOM and oomd actions
cr0x@server:~$ journalctl -k -g -i 'oom|out of memory' --since '1 hour ago' | tail -n 20
Dec 31 00:12:02 server kernel: Out of memory: Killed process 4120 (node) total-vm:2103456kB, anon-rss:980000kB, file-rss:12000kB, shmem-rss:0kB, UID:1001 pgtables:3400kB oom_score_adj:0
Dec 31 00:12:02 server kernel: oom_reaper: reaped process 4120 (node), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
cr0x@server:~$ journalctl -u systemd-oomd --since '1 hour ago' | tail -n 20
Dec 31 00:11:58 server systemd-oomd[812]: Killed /system.slice/myapp.service due to memory pressure for /system.slice.
Ce que cela signifie : Le kernel OOM killer et systemd-oomd peuvent tuer. Si oomd a tué en premier, votre « événement OOM » peut survenir avant que la RAM n’atteigne zéro.
Décision : Décidez quelle politique vous souhaitez : oomd proactif (souvent bon pour garder l’hôte réactif) ou « laisser le kernel gérer » (souvent plus bruyant). Configurez‑le délibérément.
Causes profondes : ballooning, overcommit, reclaim et pourquoi les swap storms arrivent
Le ballooning est un pari sur la stabilité des charges
Le ballooning marche bien quand :
- les guests ont une mémoire inactive prévisible
- les charges ne sont pas sensibles à la latence
- l’hôte peut dégonfler rapidement
Le ballooning marche mal quand :
- l’utilisation mémoire augmente soudainement (réchauffement du cache, déploiements, pics de trafic)
- l’hôte est lui‑même sous pression, donc la dégonflement peut ne pas arriver à temps
- le guest est configuré avec un swap généreux, masquant les signaux d’alerte précoces
Double reclaim : le guest swap, l’hôte swap, tout le monde perd
Les incidents les plus coriaces impliquent du reclaim à deux couches. Le guest swappe parce que sa « mémoire physique » balloonée a rétréci. L’hôte swappe parce qu’il a trop sur‑engagé. Maintenant chaque page‑in du guest peut déclencher des page‑in de l’hôte. La latence devient une poupée matriochka.
L’overcommit mémoire est une décision de politique, pas un héritage
Il y a trois idées d’« overcommit » que les gens confondent :
- Overcommit de l’hyperviseur : allouer plus de vRAM total que la RAM de l’hôte, en supposant que toutes les VMs ne picnent pas en même temps.
- Overcommit mémoire virtuelle Linux : permettre aux processus d’allouer plus de mémoire virtuelle que RAM+swap, basé sur des heuristiques.
- Overcommit densité container : planifier des pods/containeurs avec des requests mémoire inférieures aux limites, en pariant sur la moyenne.
Chacun peut être sensé. Superposez les trois et vous construisez une machine à catastrophe pour les charges en pointe.
Les swap storms sont généralement déclenchées par quatre motifs
- La cible du ballon change trop agressivement (événement de pression hôte, automatisation « right‑sizing », ou un humain voulant être malin).
- Un service basé sur un heap croît jusqu’à la thrasher GC, puis commence à faulter comme un fou une fois swapé.
- Le cache de fichiers n’est pas le problème mais vous touchez quand même aux knobs cache et affamez la mémoire anonyme.
- Lenteur d’IO retarde le reclaim (voisin bruyant stockage, RAID dégradé, rafales de snapshots), poussant le système vers des stalls de reclaim direct.
Gardez en tête une idée paraphrasée utile pour le design des limites : paraphrased idea
— Gene Kim a insisté sur le fait que la fiabilité vient de la réduction de la variance et de la prévisibilité du travail, pas des actions héroïques.
Imposer des limites sensées : VMs, conteneurs et l’hôte
« Limites sensées » signifie que vous décidez quelle couche a le droit de dire « non » en premier, et comment. Ma préférence pour les systèmes de production qui reçoivent des cris :
- Allocation dure pour les VMs critiques (ou au moins des planchers balloon stricts) pour que les guests aient une RAM prévisible.
- Limites cgroup par service pour qu’un processus en fuite ne transforme pas l’OS en banc d’essai de swap.
- oomd configuré volontairement pour tuer la bonne chose tôt, plutôt que le kernel qui tue quelque chose au hasard tardivement.
Couche VM : ne laissez pas « dynamique » signifier « surprenant »
Sur de nombreux hyperviseurs vous pouvez définir :
- mémoire min (plancher balloon)
- mémoire max (plafond)
- shares/priorité (qui obtient la mémoire en premier)
Règles pratiques qui tiennent dans le temps :
- Fixez le plancher au moins à la RSS en régime constant observée + marge de sécurité, pas « la moitié du max parce que ça a l’air bien ».
- Pour les bases de données et JVM, les planchers doivent être conservateurs ; récupérer leur working set nuit immédiatement.
- Désactivez le ballooning pour les charges extrêmement sensibles à la latence ou sujettes à des pics, sauf si vous avez prouvé que c’est sans danger lors de tests de charge.
Couche conteneur : memory.max est votre ceinture de sécurité
Si vous exécutez des conteneurs directement sous systemd (ou même juste des services), cgroup v2 est déjà présent dans Ubuntu 24.04. Utilisez‑le.
Exemple : définir une limite soft et hard pour un service systemd
cr0x@server:~$ sudo systemctl set-property myapp.service MemoryHigh=6G MemoryMax=7G
cr0x@server:~$ systemctl show myapp.service -p MemoryHigh -p MemoryMax
MemoryHigh=6442450944
MemoryMax=7516192768
Ce que cela signifie : Le service sera ralenti autour de 6 GiB et tué à 7 GiB (selon le comportement et la politique oomd/kernel).
Décision : Choisissez des limites basées sur des tests de charge et la RSS observée. Si vous ne pouvez pas tester, commencez prudent et surveillez memory.events.
Couche hôte : stoppez le swap hôte avant qu’il ne commence
Le swap d’hôte est une taxe payée par chaque VM, en latence. Si votre hôte swappe, votre « voisin bruyant » est l’hôte lui‑même.
Politique hôte qui fonctionne :
- éviter des ratios d’overcommit mémoire qui reposent sur « ça ne picera jamais tous en même temps »
- garder le swap hôte minimal, ou le configurer comme frein d’urgence, pas comme voie quotidienne
- surveiller PSI sur l’hôte et alerter sur un « full » mémoire soutenu
Stratégie swap sur Ubuntu 24.04 : moins de drame, plus de contrôle
Le swap n’est pas mauvais en soi. C’est un outil. Le problème est quand il devient votre niveau mémoire principal par accident.
Choisir une approche swap adaptée à votre mode de défaillance
- Swapfile disque : simple, persistant, peut absorber les pics, mais peut causer une amplification IO sous pression.
- zram : swap compressé en RAM, rapide, réduit l’IO disque, mais utilise le CPU et réduit la RAM effective à forts taux de compression.
- Pas de swap : force un OOM plus tôt, peut convenir aux services sans état qui redémarrent proprement, risqué pour les systèmes nécessitant une dégradation douce.
Ma position habituelle pour des VMs exécutant des charges mixtes : petit swap disque + zram (optionnel) + limites cgroup fortes. L’objectif est de survivre à de courts pics sans laisser le système entrer sournoisement dans une dette de swap permanente.
Faites du swappiness une politique, pas un folklore
Une swappiness plus faible réduit l’empressement du kernel à swapper la mémoire anonyme. Pour beaucoup de serveurs de production, 10–30 est un point de départ raisonnable. Sur postes de bureau, les valeurs par défaut peuvent convenir. Pour des guests balloonés, je préfère la baisser parce que le ballooning réduit déjà la marge de manière imprévisible.
cr0x@server:~$ sudo sysctl -w vm.swappiness=20
vm.swappiness = 20
cr0x@server:~$ printf "vm.swappiness=20\n" | sudo tee /etc/sysctl.d/99-swappiness.conf
vm.swappiness=20
Ce que cela signifie : Changement immédiat et persistant.
Décision : Si vous baissez swappiness, assurez‑vous aussi d’avoir assez de marge RAM ; sinon vous atteindrez l’OOM plus vite. Cela peut être souhaitable — si c’est planifié.
Quand zram aide (et quand il n’aide pas)
zram peut être salvateur durant une swap storm car il remplace l’IO lent par une compression plus rapide. Mais ce n’est pas gratuit : sous pression soutenue, le CPU peut devenir le prochain goulot. Utilisez‑le quand votre mode de défaillance est lié à l’IO wait et aux défauts majeurs, pas quand votre CPU est déjà saturé.
Vérification rapide : avez‑vous déjà zram ?
cr0x@server:~$ swapon --show
NAME TYPE SIZE USED PRIO
/swapfile file 8G 6.7G -2
/dev/zram0 partition 2G 0B 100
Ce que cela signifie : zram existe et a une priorité plus élevée (100) que le swapfile (-2), ce qui est correct si vous choisissez cette approche.
Décision : Si vous voyez le swap disque frappé alors que zram est inutilisé, les priorités sont erronées. Corrigez les priorités ou désactivez un des backends de swap.
Blague n°2 (courte, pertinente) : La seule chose qui croît plus vite que l’usage du swap, c’est la confiance de celui qui « a juste augmenté le swapfile ».
Comportement OOM : kernel OOM killer vs systemd-oomd
Ubuntu 24.04 garde souvent systemd‑oomd disponible. Le kernel OOM killer est le dernier recours quand le noyau ne peut plus allouer de mémoire. systemd-oomd est un moteur de politique qui peut tuer plus tôt sur la base de signaux de pression (PSI) et des frontières cgroup.
Pourquoi vous devriez vous en soucier
Si vous vous attendez à « OOM seulement quand la RAM est à 100% », vous serez surpris. oomd peut tuer un service alors que le système est techniquement encore vivant mais profondément ralenti. Ce n’est pas de la méchanceté. C’est du triage.
Ce qu’il faut configurer
- Assurez‑vous que les services critiques sont protégés (ou séparés) pour que oomd ne tire pas sur la mauvaise cible.
- Placez vos charges principales dans des slices dédiées avec des budgets mémoire clairs.
- Décidez si « tuer le plus gros coupable » est correct, ou si vous préférez « tuer le moins important » via la structure et les priorités des unités.
Vérifier si oomd est activé
cr0x@server:~$ systemctl is-enabled systemd-oomd
enabled
Ce que cela signifie : oomd agira s’il est configuré/déclenché par la pression et les réglages d’unité.
Décision : Si vous exécutez des charges multi‑tenant sur une VM, oomd est souvent votre ami. Si vous avez un monolithe critique avec des SLOs stricts, vous préférerez peut‑être plafonner la mémoire strictement et laisser le kernel OOM à l’intérieur d’un cgroup contrôlé.
PSI : mesurer la pression plutôt que deviner
PSI vous dit combien de temps les tâches passent bloquées à cause d’un contentieux de ressources. Le PSI mémoire est le meilleur indicateur « le système souffre vraiment » que j’ai utilisé ces dernières années. C’est mieux que « RAM utilisée » et plus honnête que « load average ».
À quoi ressemble un bon profil
some avg10en faibles unités pendant les pics est souvent acceptable.full avg10devrait être proche de zéro pour les services sensibles à la latence.
À quoi ressemble un mauvais profil
full avg10soutenu au‑dessus d’environ 1–2% sur des nœuds de production signifie généralement que la latence tail est déjà cassée.some avg10au‑dessus d’environ 20–30% suggère une pression chronique. Votre système passe un tiers de son temps à attendre la mémoire. Ce n’est pas un style de vie.
Vérifiez aussi le PSI CPU (les swap storms peuvent se déguiser en pression CPU à cause du reclaim) :
cr0x@server:~$ cat /proc/pressure/cpu
some avg10=9.12 avg60=6.10 avg300=2.00 total=55555555
full avg10=0.00 avg60=0.00 avg300=0.00 total=0
Ce que cela signifie : Le CPU est occupé mais pas saturé d’une manière qui bloque toutes les tâches. Si le PSI mémoire est élevé et le PSI CPU modéré, la mémoire est le coupable.
Décision : N’« augmentez pas le CPU » pour régler un stall mémoire. Vous aurez juste un stall plus rapide.
Trois mini‑récits d’entreprise venus des tranchées
Mini‑récit 1 : L’incident causé par une mauvaise hypothèse
L’entreprise : un fournisseur SaaS de taille moyenne avec un mix d’APIs orientées client et de workers en arrière‑plan. L’équipe plateforme a déployé des guests Ubuntu 24.04 sur un cluster KVM. Ils ont aussi activé le ballooning parce que le cluster était « plutôt inactif la nuit », et les tableaux de bord rendaient ça sûr.
L’hypothèse erronée était subtile : « Si l’hôte a de la mémoire libre, le guest peut toujours récupérer de la mémoire rapidement. » En réalité, l’allocation hôte avait beaucoup de mémoire libre en agrégé, mais elle n’était pas disponible là où la VM en avait besoin au moment voulu à cause de VMs concurrentes qui piquaient ensemble et de cibles ballon changeant vite.
L’étage API a pris le premier coup. Les requêtes ont commencé à timeout, mais le CPU n’était pas saturé. Les ingénieurs ont cherché une régression réseau imaginée. L’indice était caché en pleine vue : les majors faults ont grimpé, et le PSI mémoire full a dépassé 5% pendant des minutes.
Finalement, le kernel OOM killer a été accusé d’avoir « tué au hasard » un processus Node. Ce n’était pas aléatoire. C’était celui qui touchait le plus de pages swapées tout en tenant le trafic client. Le postmortem n’a pas été compliqué : augmenter le plancher du ballon au‑dessus du RSS en régime, définir des limites cgroup par service, et alerter sur PSI et taux de swap‑in plutôt que sur « RAM utilisée ».
Mini‑récit 2 : L’optimisation qui s’est retournée
Une autre organisation, mêmes problèmes. Ils étaient fiers de leur contrôle des coûts. Quelqu’un a proposé de réduire les allocations mémoire VM parce que « Linux utilise la mémoire libre pour le cache de toute façon ». Vérité, mauvaise application.
Ils ont réduit la vRAM, puis essayé de compenser en augmentant la taille du swap « pour éviter les OOM ». La première semaine semblait aller : moins d’OOM, moins d’alertes. Puis est arrivé la charge de fin de mois, avec des requêtes de reporting plus lourdes et un batch qui réchauffait de grandes structures en mémoire.
Le système n’a pas planté ; il est juste devenu inutilisable. C’est le pire type de panne car ça déclenche des retries et des timeouts, pas un redémarrage propre. Les graphiques de stockage montraient une utilisation élevée ; tout le monde regardait le SAN comme s’il avait commis une trahison personnelle.
Cause racine : la VM était entrée dans une dette de swap soutenue. Le swap plus grand a retardé l’OOM, mais il a aussi permis à l’empreinte mémoire de dépasser la capacité efficace de la VM. L’« optimisation » a transformé un échec net en une panne au ralenti. La correction : swap plus petit, caps mémoire stricts par service, et une politique qui dit : pour les services latency‑tier, le swap est traité comme un incident, pas comme un mécanisme d’adaptation.
Mini‑récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une société liée à la finance exécutait quelques nœuds PostgreSQL critiques en VM. Ils avaient la réputation d’être conservateurs — parfois agaçamment. Pas de ballooning sur les VMs DB. Allocations mémoire fixes. Réservations hôte strictes. Ennuyeux.
Un jour, un cluster voisin a eu une fuite mémoire sur un ensemble de workers. Les hôtes ont commencé à ressentir la pression. Sur les charges d’une autre équipe, le rayon d’action a été moche : les cibles balloon ont changé, les guests ont swapé, et la latence a grimpé. Mais les VMs DB sont restées stables. Elles étaient protégées par la politique, pas par la chance.
L’équipe DB a quand même dû gérer des effets en aval (apps timeouting, tempêtes de connexions), mais leurs nœuds n’ont pas rejoint le chaos. Ça comptait : des bases de données stables vous donnent des options. Vous pouvez délester la charge, drainer le trafic, et récupérer avec moins de pièces en mouvement.
La leçon post‑incident n’était pas glamour : ils ont continué la chose ennuyeuse — réserver de la mémoire pour les systèmes état, limiter tout le reste, et traiter l’overcommit comme un risque contrôlé avec surveillance. Parfois, la meilleure optimisation est de refuser d’optimiser la mauvaise chose.
Erreurs courantes : symptôme → cause → correction
1) « Le CPU est élevé, donc c’est forcément du calcul »
Symptôme : load average élevé, temps système CPU élevé, latence haute, mais CPU utilisateur pas si élevé.
Cause racine : overhead de reclaim et de page fault (reclaim direct, kswapd), souvent déclenché par du ballooning ou une fuite mémoire.
Correction : Vérifiez PSI et les majors faults. Réduisez la pression mémoire d’abord : augmentez le plancher VM / réduisez le ballooning / limitez les services / corrigez la fuite. Puis revisitez le sizing CPU.
2) « On a de la mémoire libre sur l’hôte, donc le guest ne devrait pas swapper »
Symptôme : le guest swappe fortement ; l’hôte montre de la mémoire disponible ; les gens débattent des graphes.
Cause racine : le guest voit sa mémoire balloonée ; la politique et le timing de l’hyperviseur font que « libre » n’égale pas « disponible pour ce guest maintenant ».
Correction : Fixez des planchers balloon et stoppez les cibles agressives. Pour les VMs critiques, désactivez le ballooning ou utilisez des réservations statiques.
3) « On va juste ajouter du swap »
Symptôme : moins de kills OOM, mais plus de timeouts et des chutes de performance plus abruptes sous charge.
Cause racine : le swap devient une béquille qui laisse l’empreinte mémoire dépasser la capacité du working set.
Correction : Gardez le swap modéré. Utilisez des limites cgroup et oomd pour échouer vite et récupérer, ou allouez plus de RAM.
4) « Tuner swappiness va régler la tempête »
Symptôme : quelqu’un met swappiness à 1 pendant un incident ; rien ne s’améliore.
Cause racine : une fois en thrash, le système est déjà endetté ; les knobs de politique ne font pas revenir instantanément les pages swapées.
Correction : Mitigation immédiate : réduire la demande mémoire ou augmenter la mémoire réelle. Appliquez les changements de swappiness après stabilisation, puis validez en test de charge.
5) « Le kernel OOM killer est aléatoire »
Symptôme : différents processus meurent à chaque fois ; les gens concluent que Linux est imprévisible.
Cause racine : le scoring OOM dépend de l’usage mémoire et ajustements ; sous pression, la « meilleure » victime change avec le timing de la charge.
Correction : Mettez les charges dans des cgroups avec des budgets mémoire explicites, définissez OOMScoreAdjust pour les services critiques, et comptez sur oomd pour des kills politiques plus précoces.
6) « Le cache me vole la RAM » (la plainte éternelle)
Symptôme : free montre peu de mémoire libre ; panique générale ; on vide les caches.
Cause racine : mauvaise compréhension du page cache Linux vs mémoire disponible ; vider les caches cause des pics IO et peut aggraver la latence.
Correction : Utilisez MemAvailable, PSI et majors faults. Ne videz les caches qu’en tests contrôlés, pas en intervention de production.
Checklists / plan pas à pas
Pas à pas : stabiliser une swap storm active (guest)
- Confirmer que c’est une vraie pression : lancez
vmstat, vérifiezsi/so, faitescat /proc/pressure/memory. - Identifier le coupable :
ps ... --sort=-rss, vérifiez le swap par processus via/proc/<pid>/smaps_rollup. - Stopper la croissance : bridez le service avec
systemctl set-property ... MemoryMax=ou réduisez workers/heap. - Coordonner avec l’hyperviseur : augmentez la mémoire allouée ou réduisez la cible/plancher du balloon. Souvent la solution la plus rapide.
- Redémarrer stratégiquement : redémarrez les processus critiques les plus swapés après avoir réduit leur appétit mémoire. Redémarrer sans corriger l’appétit rejoue l’incident.
- Surveiller la récupération : les majors faults et PSI doivent chuter en premier. Le swap utilisé peut rester élevé ; ça va si le swap‑in cesse et que la latence revient.
Pas à pas : prévenir la récurrence (politique)
- Choisir la couche de reclaim : préférez les limites côté guest (cgroup et oomd) plutôt que le ballooning hôte surprise.
- Fixer des planchers VM : assurez‑vous que le minimum balloon couvre le steady‑state RSS + marge de burst pour chaque classe de VM.
- Définir des budgets par service : utilisez
MemoryHigh/MemoryMaxet validez viamemory.events. - Dimensionner le swap correctement : swap petit à modéré ; envisagez zram avec priorité correcte ; traitez le taux de swap‑in comme une métrique alertable.
- Alerter sur PSI : surtout
memory full avg10. Il capte la « mort lente » plus tôt que la plupart des dashboards. - Tester la charge avec le ballooning activé : si vous insistez sur le ballooning, testez‑le sous concurrence de pics réalistes avec churn mémoire réaliste.
- Documenter le comportement de kill : quels services peuvent mourir en premier, et comment ils se rétablissent (politiques restart systemd, timeouts d’arrêt gracieux).
Pas à pas : vérification de sanity après modifications
- Lancez une charge contrôlée. Capturez
free -h, PSI,sar -B,iostat -x. - Vérifiez l’application des cgroups :
memory.eventsdoit refléter vos seuils pendant le stress, pas seulement après un désastre. - Confirmez qu’aucun swap hôte n’intervient sous pics normaux (si vous contrôlez l’hôte). Si l’hôte swappe, votre politique plateforme se moque de vous.
FAQ
1) Le swap est‑il toujours mauvais sur des serveurs Ubuntu 24.04 ?
Non. Le swap est un tampon de sécurité. Il devient problématique lorsqu’il est utilisé continûment ou suffisamment intensément pour causer des majors faults et de l’IO wait. Traitez le taux de swap‑in et le PSI mémoire full comme les vrais signaux d’alerte.
2) Pourquoi mon guest swappe alors que l’hôte montre de la mémoire libre ?
Parce que la « mémoire physique » disponible du guest peut être réduite par le ballooning, indépendamment des graphes de mémoire libre de l’hôte. De plus, « libre » sur l’hôte ne signifie pas « immédiatement allouable à votre VM » en période de contention.
3) Dois‑je désactiver le ballooning ?
Pour les systèmes état critiques (bases de données, queues) et les SLOs de latence stricts : généralement oui, ou au moins définir un plancher conservateur. Pour des flottes sans état et élastiques : le ballooning peut être acceptable si vous surveillez PSI et imposez des limites fortes par service.
4) Quelle est la différence entre MemoryHigh et MemoryMax ?
MemoryHigh est un point de throttling : le noyau commencera à reclaim dans le cgroup et appliquera la pression. MemoryMax est un plafond dur : les allocations échouent et vous pouvez déclencher un OOM au sein de ce cgroup.
5) Pourquoi systemd-oomd a‑t‑il tué un service alors qu’il restait de la RAM ?
oomd peut agir sur une pression soutenue (PSI) pour garder le système réactif. Cela peut arriver avant que la RAM n’atteigne zéro, surtout sous stalls de reclaim et thrash de swap.
6) Baisser la swappiness suffit‑elle à arrêter une swap storm ?
Non. Ce n’est pas suffisant. Cela peut réduire l’empressement du kernel à swapper sous pression modérée, mais n’effacera pas une RAM sous‑dimensionnée, un ballooning agressif, ou une fuite mémoire. Réglez d’abord le dimensionnement et les limites.
7) Comment savoir si je souffre spécifiquement de majors faults ?
Utilisez sar -B (regardez majflt/s) et corrélez avec la latence. Les majors faults signifient des page‑ins depuis disque. S’ils sont élevés, votre charge attend littéralement le swap.
8) Sur quoi alerter pour détecter tôt ce problème ?
Au minimum : PSI mémoire (full et some), taux de swap‑in (vmstat si trend), majors faults, et memory.events des cgroups pour les services clés. « Pourcentage mémoire utilisé » seul est un signal faible.
9) Dois‑je utiliser zram sur des VMs de production ?
Parfois. Si vos swap storms sont liés à l’IO et que vous avez de la marge CPU, zram peut réduire fortement l’IO wait. Si vous êtes déjà CPU‑bound, zram peut échanger un goulot contre un autre.
10) Une swap storm peut‑elle ressembler à une panne stockage ?
Oui. Les swap storms génèrent beaucoup d’IO aléatoire, saturent les dispositifs, et gonflent la latence. Le stockage paraît « lent », mais il répond à une demande pathologique. Corrigez la pression mémoire et la « panne stockage » disparaît souvent.
Conclusion : prochaines étapes à appliquer aujourd’hui
Si vous retenez une chose : ballooning plus des limites faibles est la façon de construire accidentellement un générateur de swap storms. Ubuntu 24.04 vous fournit les outils pour éviter cela : contrôles cgroup v2, visibilité PSI, et une politique OOM exploitable. Utilisez‑les volontairement.
Prochaines étapes pratiques :
- Sur une VM problématique, basez‑vous :
free -h,vmstat 1,sar -B,cat /proc/pressure/memory. - Définissez des budgets mémoire par service avec
MemoryHighetMemoryMax; validez viamemory.events. - Mettez-vous d’accord sur une politique mémoire VM : planchers balloon conservateurs pour les systèmes critiques, et règles explicites pour quand le ballooning est autorisé.
- Dimensionnez le swap pour qu’il soit un tampon, pas un mode de vie. Envisagez zram seulement en connaissance de cause.
- Alertez sur la pression (PSI) et le swap‑in, pas seulement sur le « pourcentage utilisé ».
Faites cela, et le prochain « la VM semble lente » deviendra un diagnostic de cinq minutes au lieu d’un tour de blâme de trois heures.