Ubuntu 24.04 : surprises du ballooning mémoire — fixez des limites sensées et stoppez les tempêtes de swap (Cas #16)

Cet article vous a aidé ?

Cela commence par un « léger ralentissement ». Puis vos graphiques deviennent de l’art moderne : la charge moyenne augmente, des pics de latence apparaissent, les disques semblent très occupés sans rien faire d’utile, et la VM donne l’impression de fonctionner dans de la mélasse.

Sur Ubuntu 24.04 dans des environnements virtualisés, le ballooning mémoire peut passer de « fonctionnalité d’overcommit utile » à « générateur de tempêtes de swap ». Le correctif n’est que rarement mystique. Il s’agit généralement de limites, d’un meilleur comptage et d’une décision tranchée sur ce que vous voulez qu’il se passe quand la mémoire vient réellement à manquer.

Ce qui se passe réellement quand le ballooning devient problématique

Le ballooning existe parce que les hyperviseurs aiment jouer au Tetris avec la RAM. Une VM peut être configurée pour 16 Go, mais la plupart du temps elle n’utilise que 4–8 Go. Le ballooning permet à l’hôte de reprendre la partie « inutilisée » et de la prêter à d’autres VMs. En théorie, tout le monde gagne.

En pratique, le ballooning peut générer un type précis de misère :

  • L’hôte reprend de la mémoire au pire moment possible (parce que l’hôte est sous pression).
  • Le noyau de l’invité voit moins de RAM disponible et commence à réclamer des pages.
  • Si la reclamation ne trouve pas assez de page cache « propres », il commence à swapper la mémoire anonyme.
  • L’I/O de swap se produit sur des disques virtuels, souvent sur du stockage partagé, ce qui amplifie la latence.
  • Maintenant l’invité est plus lent, il progresse plus lentement, reste plus longtemps sous pression, donc swappe davantage.

Le ballooning en lui‑même n’est pas mauvais. Le ballooning non borné avec un overcommit optimiste et des garde‑fous faibles est mauvais. La façon la plus simple de le décrire : vous gérez la mémoire à deux endroits (hôte et invité) avec deux noyaux qui ne partagent pas un cerveau.

Voici la partie qui surprend sur Ubuntu 24.04 : l’écosystème par défaut autour de la pression mémoire est devenu plus « proactif ». cgroup v2 est standard, systemd est plus interventionniste, et le comportement OOM peut différer d’un ancien LTS. Rien de tout cela n’est mauvais. Cela signifie simplement que vos anciennes hypothèses peuvent échouer bruyamment.

Une citation pour rester lucide (idée paraphrasée) : l’état d’esprit de fiabilité de Gene Kranz : « Nous devons être durs et compétents — pas d’excuses. » Cela s’applique aussi aux limites mémoire.

Blague #1 : Le ballooning mémoire, c’est comme un bureau « temporaire » que vous installez dans la cuisine. C’est temporaire jusqu’à ce que le dîner soit ruiné et que vous ne retrouviez plus les fourchettes.

Faits et contexte intéressants (ce qui explique les étrangetés)

  1. Le ballooning n’est pas nouveau. VMware a popularisé les drivers balloon il y a des décennies ; le virtio-balloon de KVM l’a ensuite rendu courant dans les clouds ouverts.
  2. Linux ne considère pas le swap comme un échec par défaut. Le noyau va swapper pour préserver le cache de fichiers et lisser les pics ; c’est rationnel tant que la couche de stockage ne rend pas le swap trop coûteux.
  3. cgroup v2 a changé la donne. Le comptage mémoire est plus strict et unifié. Si vous définissez memory.max, c’est un mur réel, pas une suggestion polie.
  4. « Disponible » n’est pas « libre ». La métrique « available » de Linux estime ce qui peut être récupéré sans swap. Les gens paniquent encore en voyant « free ». Ils ne devraient pas.
  5. kswapd est un symptôme, pas un méchant. Un fort usage CPU de kswapd signifie que le noyau tente de récupérer des pages sous pression. La cause racine est presque toujours : trop peu de RAM pour l’ensemble de travail.
  6. Les tempêtes de swap sont contagieuses. Une VM qui swappe fortement peut dégrader la latence du stockage partagé, ce qui ralentit d’autres VMs, augmente leur pression mémoire et les pousse à swapper. Félicitations, vous venez d’inventer un incident de performance à l’échelle du cluster.
  7. Le ballooning peut ressembler à une fuite mémoire. Depuis l’intérieur de l’invité, on a l’impression que la RAM a disparu. Parce que c’est le cas.
  8. zram est un compromis moderne. Le swap compressé en RAM réduit l’I/O mais augmente l’usage CPU. Excellent pour certains workloads ; désastreux pour d’autres.
  9. THP peut compliquer la reclamation. Les Transparent Huge Pages peuvent rendre la reclamation et la compaction plus coûteuses en cas de pression, selon le profil de l’application.

Playbook de diagnostic rapide (premier/deuxième/troisième)

Premier : confirmer que la machine est vraiment sous pression mémoire

  • Recherchez de l’activité de swap-in/out et des défauts majeurs.
  • Confirmez si la mémoire « available » est faible et le reste.
  • Vérifiez PSI pour voir si le système se bloque lors de la reclamation mémoire.

Second : prouver si le ballooning est en cause

  • Vérifiez la présence du driver virtio_balloon et les statistiques du balloon.
  • Corrélez le comportement « host reclaimed » (si visible) avec les chutes mémoire côté invité.
  • Sur des plateformes comme Proxmox/OpenStack, comparez la mémoire configurée et la mémoire effective ainsi que les changements de target du balloon.

Troisième : identifier ce qui consomme la mémoire et si c’est récupérable

  • Top des processus par RSS et par mémoire anonyme.
  • Cache de fichiers vs usage anonyme (le page cache est votre ami… jusqu’à ce qu’il ne le soit plus).
  • Limites cgroup et plafonds mémoire par service.

Décidez du résultat souhaité

  • Si vous voulez une latence prévisible : réduisez l’overcommit, définissez des limites strictes et préférez l’OOM kill plutôt que les tempêtes de swap.
  • Si vous cherchez une consolidation maximale : autorisez le ballooning mais imposez un plancher, utilisez zram judicieusement, et surveillez PSI comme si c’était du chiffre d’affaires.

Tâches pratiques : commandes, sorties et la décision que vous prenez

Voici les tâches que j’exécute réellement quand une VM « est devenue lente mystérieusement ». Chacune inclut ce que signifie la sortie et la décision qui en découle. Exécutez‑les dans l’ordre jusqu’à obtenir une histoire cohérente. Si vous ne pouvez pas expliquer l’histoire, ne touchez pas aux réglages.

Task 1: Check the headline memory state (and don’t misread it)

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:           7.7Gi       6.9Gi       112Mi       204Mi       731Mi       402Mi
Swap:          4.0Gi       3.6Gi       128Mi

Ce que cela signifie : Available n’est que de 402 MiB et le swap est fortement utilisé. Vous êtes déjà en « mode reclamation ».

Décision : Passez immédiatement à vmstat et à PSI pour voir si ça thrash activement ou si le swap est la conséquence d’un événement passé.

Task 2: Detect active swap storm vs “swap happened earlier”

cr0x@server:~$ vmstat 1 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  1 3718920 112640  55872 634320  64  128   220   310  410  790 12  8 55 25  0
 3  2 3721048  98304  53120 621104 256  512   880  1200  610 1200 14 10 35 41  0
 4  2 3723096  94208  51456 609440 512 1024  1300  1900  720 1400 12  9 28 51  0
 3  1 3725144  90112  49664 601112 128  256   600   840  540 1100 10  7 45 38  0

Ce que cela signifie : Des si/so non nuls sur plusieurs échantillons combinés à un wa élevé indiquent un swap actif et de l’I/O en attente. Ce n’est pas un « swap ancien ».

Décision : Il faut arrêter la pression. Soit ajouter de la mémoire / réduire le ballooning / réduire la charge / soit accepter l’OOM pour limiter la zone impactée.

Task 3: Check PSI to confirm stalls (Ubuntu 24.04 has it)

cr0x@server:~$ cat /proc/pressure/memory
some avg10=18.24 avg60=12.10 avg300=5.43 total=218443992
full avg10=6.12 avg60=3.98 avg300=1.22 total=68423992

Ce que cela signifie : « some » signifie que les tâches sont retardées parfois ; « full » signifie que le système est complètement bloqué en attente de mémoire. Des valeurs « full » non triviales se corrèlent fortement avec une douleur visible par les utilisateurs.

Décision : Traitez cela comme un incident. Ne pensez pas « peut‑être le CPU » tant que la pression mémoire n’est pas résolue.

Task 4: Check if balloon driver exists (guest side)

cr0x@server:~$ lsmod | grep -E 'virtio_balloon|vmw_balloon'
virtio_balloon         24576  0

Ce que cela signifie : Le balloon virtio est présent. Cela ne prouve pas qu’il est en train de gonfler activement, mais rend le ballooning plausible.

Décision : Inspectez les statistiques du balloon pour voir si l’invité croit que de la mémoire a été retirée.

Task 5: Inspect virtio balloon stats (if exposed)

cr0x@server:~$ grep -H . /sys/devices/virtio*/balloon*/{num_pages,actual,free_page_hint} 2>/dev/null
/sys/devices/virtio0/virtio0/balloon/num_pages:2097152
/sys/devices/virtio0/virtio0/balloon/actual:1572864
/sys/devices/virtio0/virtio0/balloon/free_page_hint:1

Ce que cela signifie : « actual » indique les pages actuellement balloonées (reprises). Si ce nombre augmente durant la pression de l’hôte, votre VM verra moins de RAM utilisable.

Décision : Si les pages balloonées sont significatives par rapport au total, ne considérez plus la RAM comme « garantie ». Mettez un minimum ou désactivez le ballooning pour les VMs sensibles à la latence.

Task 6: Confirm configured memory vs what the kernel sees

cr0x@server:~$ grep -E 'MemTotal|MemAvailable' /proc/meminfo
MemTotal:        8049136 kB
MemAvailable:     411224 kB

Ce que cela signifie : MemTotal est ce que l’invité pense actuellement avoir. Si vous aviez « configuré 16G » mais que MemTotal est ~8G, le ballooning (ou le hotplug) est en cause.

Décision : Alignez vos attentes sur la réalité. Si la VM a besoin de 16G, n’autorisez pas l’hôte à la traiter comme une tirelire.

Task 7: Identify top memory consumers by RSS (fast triage)

cr0x@server:~$ ps -eo pid,comm,rss --sort=-rss | head -n 10
  PID COMMAND           RSS
 2481 java           2381440
 1822 postgres       1024320
 1999 node            612480
 1320 snapd           188224
  911 systemd-journal  123456
 2766 python3          112320

Ce que cela signifie : Vous avez de gros consommateurs de mémoire anonyme (par ex. JVM) et des services avec état. Tuer le mauvais processus peut « résoudre le swap » et aussi « supprimer votre activité ».

Décision : Pour les gros utilisateurs connus (JVM, bases de données), vérifiez la heap/les buffers configurés. La pression mémoire causée par le ballooning peut révéler des valeurs d’application trop optimistes.

Task 8: Check for kernel reclaim trouble (compaction, THP)

cr0x@server:~$ grep -E 'compact|thp' /proc/vmstat | head
compact_migrate_scanned 184221
compact_free_scanned 91234
compact_isolated 1422
thp_fault_alloc 1221
thp_collapse_alloc 18

Ce que cela signifie : Une forte activité de compaction sous pression peut augmenter le temps CPU consacré à la reclamation et bloquer les workloads. L’allocation/collapse THP peut ajouter un overhead.

Décision : Si vous voyez beaucoup de compaction avec un PSI « full », songez à ajuster THP ou à garantir plus de marge plutôt que d’« optimiser le swap ».

Task 9: Look for OOM or near-OOM events (journal)

cr0x@server:~$ journalctl -k --since "2 hours ago" | egrep -i "oom|out of memory|kswapd|memory pressure" | tail -n 20
Dec 30 09:41:12 server kernel: Memory cgroup out of memory: Killed process 1999 (node) total-vm:3128448kB, anon-rss:598112kB, file-rss:2048kB
Dec 30 09:41:12 server kernel: oom_reaper: reaped process 1999 (node), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

Ce que cela signifie : Le noyau a tué un processus à cause d’un OOM de memory cgroup. Ce n’est pas aléatoire ; c’est une limite qui a été appliquée (ou une fuite qui a atteint le mur).

Décision : Si vous préférez cela aux tempêtes de swap, très bien — rendez‑le intentionnel : définissez des limites mémoire par service et documentez‑les. Sinon, augmentez les limites ou réduisez le ballooning.

Task 10: Inspect swap devices and priorities

cr0x@server:~$ swapon --show --bytes
NAME       TYPE      SIZE        USED       PRIO
/swap.img  file  4294967296  3865051136       -2

Ce que cela signifie : Un swapfile est utilisé, priorité basse. S’il réside sur un stockage lent ou contendu, le swap punira tout le monde.

Décision : Décidez de conserver le swap (souvent oui, mais plus petit) et d’utiliser zram ou de désactiver le swap pour les VMs sensibles à la latence (avec des garde‑fous).

Task 11: Check swap behavior knobs (swappiness, vfs cache pressure)

cr0x@server:~$ sysctl vm.swappiness vm.vfs_cache_pressure
vm.swappiness = 60
vm.vfs_cache_pressure = 100

Ce que cela signifie : Valeurs proches du défaut. Sous ballooning, le noyau peut swapper plus tôt que souhaité pour certains workloads.

Décision : Pour des VMs base de données/latence, songez à réduire swappiness (par ex. 10–20) après avoir défini des limites sensées. Régler sans limites relève du souhaitalisme.

Task 12: Confirm cgroup v2 memory constraints (system-wide)

cr0x@server:~$ stat -fc %T /sys/fs/cgroup
cgroup2fs

Ce que cela signifie : Vous êtes sur cgroup v2. Ubuntu 24.04 l’utilise par défaut.

Décision : Utilisez les contrôles v2 (memory.max, memory.high, memory.swap.max). Ne suivez plus bêtement des conseils de l’ère v1.

Task 13: Check if systemd-oomd is active (it can change outcomes)

cr0x@server:~$ systemctl is-enabled systemd-oomd
enabled

Ce que cela signifie : Le démon OOM userspace peut intervenir sur la base des signaux de pression. Cela peut être bien (récupération plus rapide) ou déroutant (kills inattendus).

Décision : Si vous exécutez des workloads critiques mono‑locataire, configurez oomd pour les slices/sous‑slices ou désactivez‑le délibérément — ne le découvrez pas en pleine crise.

Task 14: Spot I/O saturation caused by swap (the “it’s storage” angle)

cr0x@server:~$ iostat -xz 1 3
Linux 6.8.0-41-generic (server) 	12/30/2025 	_x86_64_	(4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          11.01    0.00    7.32   39.88    0.00   41.79

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
vda              42.0   1120.0     0.0   0.00   18.5    26.7      51.0   2496.0     2.0   3.77   44.2    48.9     3.3   95.0

Ce que cela signifie : %util élevé, await élevé et beaucoup de petites écritures : churn de swap classique sur disque virtuel.

Décision : Réparez d’abord la pression mémoire. Le tuning stockage ne rattrapera pas une VM qui se swappe à mort sur un backing partagé.

Task 15: Confirm whether you’re in a VM and which hypervisor (helps pick the right knobs)

cr0x@server:~$ systemd-detect-virt
kvm

Ce que cela signifie : Guest KVM. Le ballooning est probablement basé sur virtio ; qemu-guest-agent peut être pertinent selon la plateforme.

Décision : Sur des stacks KVM, décidez : désactiver le ballooning pour les workloads critiques, ou fixer un plancher et surveiller les changements de target du balloon.

Task 16: Check memory.high/memory.max for a specific service (real culprit in modern systems)

cr0x@server:~$ systemctl show -p ControlGroup -p MemoryMax -p MemoryHigh nginx.service
ControlGroup=/system.slice/nginx.service
MemoryMax=infinity
MemoryHigh=infinity

Ce que cela signifie : Pas de contrôle mémoire explicite. Si nginx n’est pas le gros utilisateur, tant mieux. Pour les services gourmands, « infinity » signifie qu’ils peuvent se concurrencer jusqu’à nuire à toute la machine.

Décision : Mettez des limites mémoire sur la poignée de services qui peuvent croître de façon imprévisible (workers, JVM, outils de build, jobs batch).

Fixer des limites sensées : hyperviseur, invité et cgroup v2

Le ballooning devient gérable quand vous mettez des bornes. En production, le « partage non borné » n’est qu’une panne optimiste.

1) Décidez votre contrat mémoire : garanti, élastique ou best‑effort

Chaque VM devrait avoir l’un de ces contrats :

  • Garanti : mémoire réservée. Ballooning désactivé ou minimum proche du max. Utilisé pour bases de données, services plan de contrôle, SLOs de latence.
  • Élastique (burstable) : un certain reclaim est autorisé, mais il y a un plancher dur. Pour les couches web, caches, serveurs d’applications pouvant réduire la charge.
  • Best‑effort : ballooning activé, plancher bas, peut swapper/oom. Pour dev, CI, batch, workers éphémères.

2) Sur l’hyperviseur : cessez de promettre la même RAM à tout le monde

Quel que soit le stack (libvirt brut, Proxmox, OpenStack), le concept est le même :

  • Définissez une mémoire maximale (ce que la VM pourrait avoir).
  • Définissez une mémoire minimale / réservation (ce qu’elle doit toujours garder).
  • Limitez l’overcommit au niveau hôte à quelque chose que vous pouvez supporter quand les workloads s’alignent mal.

Pourquoi ? Parce que la reclamation n’est pas gratuite. L’invité peut devoir swapper des pages anonymes pour satisfaire l’inflation du balloon, et votre stockage paiera l’addition.

3) Dans l’invité : utilisez les limites cgroup v2 pour forcer la contention locale

Si vous ne pouvez pas contrôler parfaitement l’hôte (bienvenu sur Terre), vous pouvez au moins contenir les dégâts côté invité. cgroup v2 vous donne trois gros outils :

  • memory.max : la limite dure. La dépasser provoque un OOM kill dans ce cgroup.
  • memory.high : une limite souple. Le noyau va throttle/reclaimer pour maintenir l’usage autour de cette valeur.
  • memory.swap.max : plafonne l’usage du swap par cgroup (puissant pour empêcher qu’un seul service n’engendre une tempête de swap).

Pour les services gérés par systemd, vous définissez généralement cela via des overrides d’unité. Voici ce que cela donne pour un service worker « burstable mais borné ».

cr0x@server:~$ sudo systemctl edit worker.service
[Service]
MemoryHigh=2G
MemoryMax=3G
MemorySwapMax=512M

Ce que cela signifie : Le service peut utiliser de la mémoire, mais il ne peut pas absorber toute la machine. S’il dépasse 3G, il est tué plutôt que de pousser la VM entière en swap.

Décision : Utilisez‑le pour des composants non fiables ou en rafale : jobs background, consommateurs de messages, « encore un exporter », et tout ce qui est écrit dans un langage susceptible de découvrir l’infini.

4) Rendez les décisions OOM délibérées : kernel vs systemd-oomd

Ubuntu 24.04 peut impliquer systemd-oomd, qui agit selon PSI et la pression mémoire des cgroups. Ce n’est pas le classique OOM killer du noyau. Déclencheur différent, comportement différent, parfois plus précoce, souvent plus propre.

Ce que vous faites :

  • Si vous voulez une contention stricte par service, gardez oomd activé et gérez les slices.
  • Si vous avez un monolithe critique unique et qu’oomd pourrait tuer le mauvais processus, ajustez‑le ou désactivez‑le — mais seulement après avoir mis en place d’autres mécanismes de containment (réservations, limites).
cr0x@server:~$ systemctl status systemd-oomd --no-pager
● systemd-oomd.service - Userspace Out-Of-Memory (OOM) Killer
     Loaded: loaded (/usr/lib/systemd/system/systemd-oomd.service; enabled; preset: enabled)
     Active: active (running) since Mon 2025-12-30 08:01:12 UTC; 2h 10min ago

Ce que cela signifie : Il tourne et agira si des slices franchissent des seuils de pression.

Décision : Si vous ne l’aviez pas planifié, planifiez maintenant. « Coupures de processus surprises » n’est pas une stratégie de monitoring.

Arrêter les tempêtes de swap : choix de swap, swappiness et contrôle de la pression

Le swap n’est ni purement bon ni purement mauvais. C’est un outil. Dans les VMs, c’est aussi un piège de performance parce que l’I/O de swap est souvent le chemin le plus lent et le plus contendu de toute la chaîne.

Choisissez votre modèle de swap

Vous voulez généralement une de ces options :

  • Petit swap + faible swappiness : Suffisant pour éviter un OOM catastrophique lors de petits pics, mais pas assez pour soutenir un thrash prolongé.
  • zram swap : Swap en RAM avec compression. Réduit l’I/O disque mais consomme du CPU. Bien pour le dev et les workloads en rafale ; à évaluer pour la production liée au CPU.
  • Pas de swap (rarement correct) : Seulement lorsque vous avez de strictes réservations et que vous préférez un échec immédiat plutôt qu’un comportement dégradé. Fonctionne mieux avec de bonnes limites et de l’alerte.

Task: See whether you’re using zram already

cr0x@server:~$ lsblk -o NAME,TYPE,SIZE,MOUNTPOINT | grep -E 'zram|swap'
zram0 disk  2G

Ce que cela signifie : Un device zram existe. Il peut ou non être configuré en tant que swap.

Décision : Confirmez avec swapon --show. Si vous avez zram et swap disque, définissez les priorités intentionnellement.

Task: Set swappiness persistently (only after you fix limits)

cr0x@server:~$ sudo tee /etc/sysctl.d/99-memory-sane.conf >/dev/null <<'EOF'
vm.swappiness=15
vm.vfs_cache_pressure=100
EOF
cr0x@server:~$ sudo sysctl --system | tail -n 5
* Applying /etc/sysctl.d/99-memory-sane.conf ...
vm.swappiness = 15
vm.vfs_cache_pressure = 100

Ce que cela signifie : Le noyau privilégiera la reclamation du cache plutôt que le swap de la mémoire anonyme par rapport au comportement par défaut, même s’il peut toujours swapper en cas de vraie pression.

Décision : Si la VM swappe parce que le ballooning a retiré de la RAM, régler swappiness aide en marge. Le fix principal reste d’empêcher que la RAM soit volée en premier lieu.

Cap swap per service (the underrated fix)

Les tempêtes de swap commencent généralement avec un processus gourmand. Si vous plafonnez son swap, il ne pourra pas étaler sa souffrance sur toute la machine.

cr0x@server:~$ sudo systemctl set-property batch-jobs.service MemorySwapMax=0
cr0x@server:~$ systemctl show -p MemorySwapMax batch-jobs.service
MemorySwapMax=0

Ce que cela signifie : Ce service ne peut pas utiliser le swap. S’il manque de mémoire, il sera OOM‑killed dans son cgroup.

Décision : Appliquez‑le aux workloads où « swapper lentement pendant 30 minutes » est pire que « échouer vite et réessayer ». Le traitement par lot est un candidat idéal.

Understand why swap storms feel like storage failures

En tant qu’ingénieur stockage, je le dis clairement : une VM qui swappe fortement est indiscernable d’une attaque par déni de service sur le stockage — sauf que c’est auto‑infligé et authentifié.

Le swap produit :

  • De petites écritures aléatoires (page‑outs), plus des lectures sur défauts.
  • Des files d’attente élevées et une latence accrue.
  • Des devices de backing contendus (surtout sur des pools SSD partagés ou du stockage réseau).

Quand vous voyez un « incident de latence stockage » et qu’un invité swappe, réglez d’abord le contrat mémoire de l’invité. Puis parlez d’IOPS.

Blague #2 : Les tempêtes de swap sont le seul système météorologique qui se forme à l’intérieur, et il réussit quand même à faire tomber votre service.

Trois mini‑récits d’entreprise (comment cela échoue en vrai)

Mini‑récit #1 : La panne causée par une fausse hypothèse

L’entreprise croyait fermement : « La mémoire configurée est une mémoire garantie. » Ils exploitaient d’anciens invités Ubuntu sur un cluster KVM avec ballooning activé depuis des années, et la plupart des VMs ne se plaignaient jamais. Les dashboards montraient chaque VM « avait 16 GB », donc les équipes dimensionnaient les applications en conséquence.

Puis un incident au niveau hôte survint : un nœud physique perdit un canal DIMM et le cluster rééquilibra. L’overcommit était toujours activé. Le scheduler empaqueta fortement les workloads pour maintenir la capacité. Le ballooning se gonfla sur plusieurs invités à la fois, parce que l’hôte avait besoin de mémoire immédiatement, pas poliment.

À l’intérieur d’une VM critique Ubuntu 24.04, MemTotal n’a pas changé dans les têtes, mais effectivement si : available a chuté, la reclamation a grimpé, et le noyau a commencé à swapper des parties d’un heap JVM. La latence a augmenté, les files de requêtes ont grossi, ce qui a maintenu plus longtemps la rétention du heap. Une boucle de rétroaction avec une belle interface.

L’équipe a d’abord chassé le steal CPU et le « noisy neighbor storage ». Les deux étaient réels, mais secondaires. L’événement primaire était le retrait de mémoire via le ballooning durant la pression de l’hôte. Leur hypothèse était fausse : la mémoire configurée n’était pas une promesse ; c’était un maximum.

Le correctif fut ennuyeux et efficace : désactiver le ballooning pour la couche SLO, définir des réservations hôte pour les VMs critiques, et arrêter d’overcommitter la mémoire sur les nœuds portant des services d’état. Le coût a augmenté un peu. Les incidents ont fortement diminué.

Mini‑récit #2 : L’optimisation qui a mal tourné

Une autre organisation a voulu être maligne : ils ont activé le ballooning partout et réduit la taille de base des VMs, misant sur « Linux utilise le cache et peut le rendre ». Ils avaient techniquement raison, et opérationnellement imprudents.

Pendant quelques semaines, tout alla bien. La finance était contente. Puis un déploiement a poussé une nouvelle build qui augmentait l’usage mémoire d’un service d’indexation background. Pas une fuite — juste plus de structures de données.

Sous ballooning, ces VMs vivaient sur le fil. Quand l’indexeur a sursauté, l’invité a récupéré le page cache et a commencé à swapper. Le débit de l’indexeur a chuté, il a tourné plus longtemps et est resté chaud en mémoire plus longtemps. Pendant ce temps, l’I/O de swap a touché le même pool de stockage utilisé par les volumes de base de données.

L’« optimisation » est devenue un incident de dégradation multi‑service : requêtes web en timeout, commits base ralentis, et on‑call qui regardait des graphs de stockage en se demandant pourquoi la latence d’écriture avait explosé pendant « faible trafic ». Ce n’était pas du faible trafic ; c’était du swap élevé.

Ils ont rollbacké le déploiement et vu une récupération partielle, mais la vraie solution fut architecturale : séparer les couches par contrat mémoire, fixer des planchers de balloon, et appliquer des caps mémoire par service pour qu’une tâche background ne transforme pas tout le cluster en catastrophe au ralenti.

Mini‑récit #3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Celle‑ci est moins dramatique, ce qui est le propos. Une équipe faisait tourner des invités Ubuntu 24.04 pour des runners CI internes et une petite API production. Ils avaient une règle stricte : les VMs production avaient le ballooning désactivé, le swap limité, et des limites systemd pour les services. Les runners CI étaient best‑effort et jetables.

Un jour, le cluster hyperviseur a subi une pression mémoire inattendue après qu’une mise à jour firmware du vendeur ait changé les caractéristiques power/performance. L’hôte a commencé à récupérer agressivement. Plusieurs VMs best‑effort ont ralenti immédiatement.

La production est restée stable. Pas parce qu’elle avait « plus de mémoire », mais parce qu’elle avait une vraie réservation et aucun reclaim balloon. Les VMs API avaient un petit swap, un swappiness bas, et un memory.max sur une unité background de traitement de logs. Quand la pression a augmenté, l’unité background est morte et redémarrée. La latence de l’API a à peine bougé.

Le post‑mortem fut court : « La pression mémoire hôte a affecté la couche best‑effort. La production est restée indemne grâce aux réservations et limites de services. » Pas d’héroïsme, pas de plongée noyau, pas de threads Slack pour le soutien émotionnel.

Ils n’ont pas gagné de prix. Ils ont livré des fonctionnalités à l’heure pendant que les autres apprenaient, encore, que la prévisibilité s’achète avec des contraintes.

Erreurs courantes : symptôme → cause racine → correctif

1) Symptom: load average skyrockets, CPU usage looks moderate

Cause racine : pression mémoire bloquante et I/O wait dû au swap. La charge inclut des tâches en attente d’I/O et de reclamation, pas seulement de l’exécution CPU.

Fix : Confirmez avec vmstat (si/so), iostat (await/util) et PSI. Puis réduisez le ballooning et/ou ajoutez de la marge mémoire. Baissez swappiness seulement après avoir fixé le contrat.

2) Symptom: “We have 16 GB configured, but MemTotal is ~8 GB”

Cause racine : Ballooning/hotplug signifie que l’invité ne détient pas actuellement la mémoire maximale.

Fix : Définissez un minimum/réservation de balloon sur l’hyperviseur pour cette VM, ou désactivez le ballooning pour cette couche. Vérifiez en relisant MemTotal et les stats du balloon.

3) Symptom: swap usage keeps growing even when traffic is flat

Cause racine : L’ensemble de travail dépasse la RAM après reprise ballooning ; le noyau swappe des pages anon pour survivre.

Fix : Augmentez la mémoire garantie ou réduisez le reclaim. Si la croissance est liée à un seul service, plafonnez‑le avec cgroup v2 memory.max et memory.swap.max.

4) Symptom: random process kills that look “unpredictable”

Cause racine : systemd-oomd ou OOM mémoire cgroup applique des limites (ou les règles de slice par défaut).

Fix : Rendre le contrôle mémoire explicite : définissez MemoryMax/High sur les services, créez des slices, et décidez quels composants doivent mourir en premier. Examinez la config d’oomd au lieu de supposer un OOM noyau seulement.

5) Symptom: storage latency incident with no obvious heavy workload

Cause racine : churn de swap d’une VM génère des I/O constantes et petites. Sur du stockage partagé, cela ressemble à des voisins bruyants.

Fix : Trouvez l’invité qui swappe via iostat/vmstat dans l’invité et les métriques hôte. Arrêtez la pression mémoire. Le tuning stockage ne résoudra pas un churn de swap soutenu.

6) Symptom: “We disabled swap and now we crash more”

Cause racine : Pas de tampon pour les pics transitoires ; et pas de containment par service, donc un pic déclenche un OOM global.

Fix : Réintroduisez un petit swap ou zram, mais ajoutez des limites cgroup pour contenir les pics. Préférez le fail‑fast pour les services non critiques avec MemorySwapMax=0.

7) Symptom: high kswapd CPU and frequent stutters during GC or compaction

Cause racine : Overhead de reclamation et de compaction sous pression mémoire, possiblement amplifié par le comportement THP.

Fix : Ajoutez de la marge et réduisez le ballooning en priorité. Ensuite envisagez de changer le mode THP pour certains workloads si la compaction est un poste de coût récurrent.

Checklists / plan pas‑à‑pas

Étape par étape : stabiliser une VM Ubuntu 24.04 en swap maintenant

  1. Prouvez qu’il s’agit de pression mémoire : lancez free -h, vmstat 1 10, et cat /proc/pressure/memory. Si PSI full est non trivial et si/so sont actifs, vous êtes dans une tempête de swap.
  2. Trouvez le gourmand : utilisez ps trié par RSS. Confirmez s’il s’agit d’un seul processus ou d’une pression large.
  3. Vérifiez le ballooning : confirmez que virtio_balloon est chargé et inspectez les stats du balloon. Si MemTotal est inférieur à l’attendu, considérez‑le comme du reclaim balloon jusqu’à preuve du contraire.
  4. Réduisez le mal immédiat : si un service background est responsable, cappez‑le avec MemoryMax et éventuellement MemorySwapMax. Redémarrez le service pour revenir à un état stable.
  5. Évitez les dégâts collatéraux sur le stockage : si le swap martèle le disque, réduisez la charge ou scalez temporairement. Ne « tunez pas iostat ».
  6. Rendez le correctif permanent : décidez du contrat mémoire de la VM et ajustez les réservations/ballooning hôte et les limites invité en conséquence.

Checklist : décisions de configuration qui empêchent les incidents répétés

  • Pour chaque VM : classifiez‑la en garanti/élastique/best‑effort. Notez‑le.
  • Pour les VMs garanties : désactivez le ballooning ou fixez un minimum élevé. Évitez le swap important ; gardez un petit swap de sécurité si tolérable.
  • Pour les VMs élastiques : fixez un minimum balloon, utilisez cgroup memory.high/max pour les services connus gourmands, et songez à des caps de swap.
  • Pour les best‑effort : autorisez le ballooning, mais implémentez des retries et de l’automatisation. Traitez l’OOM comme un mode normal d’échec.
  • Monitoring : alertez sur PSI memory full, taux soutenu de swap‑out, et pics disk await/util corrélés au swap.
  • Change management : tout changement de politique d’overcommit hôte est un changement en production. Faites‑le passer par la même revue qu’une migration de base de données.

Checklist : « arrêter d’empirer » pendant un incident

  • Ne redémarrez pas en premier. Rebooter peut masquer la cause et garantit une indisponibilité.
  • Ne augmentez pas la taille du swap comme réponse primaire. Cela prolonge souvent la fenêtre de souffrance.
  • Ne « droppez les caches » pas en réflexe. Si la pression concerne la mémoire anonyme, vider le cache ne règle rien et peut augmenter les lectures disque.
  • Ne changez pas cinq sysctls en même temps. Vous ne saurez pas ce qui a aidé, et le futur vous détestera.

FAQ

1) Le ballooning mémoire est‑il toujours mauvais ?

Non. Il est utile pour la consolidation et les workloads en rafale. Il est nuisible quand vous le traitez comme invisible et qu’il reprend de la mémoire à des services critiques de latence ou d’état.

2) Comment savoir si le ballooning est la cause et non une fuite applicative ?

Cherchez un écart entre « ce que vous pensez que la VM a » et MemTotal dans /proc/meminfo, plus des variations des stats virtio balloon. Une fuite montre généralement une augmentation continue du RSS d’un processus indépendamment des changements de target du balloon.

3) Dois‑je désactiver le swap sur les VMs Ubuntu 24.04 pour éviter les tempêtes de swap ?

Parfois, mais rarement comme premier geste. swapoff sans réservations mémoire ni limites par service transforme le « lent et dégradé » en « rapide et mort ». Préférez un petit swap + containment, ou zram quand approprié.

4) Quel est le meilleur indicateur unique pour alerter ?

Le PSI mémoire « full » soutenu au‑dessus d’un petit seuil est difficile à ignorer car il mesure directement le temps perdu en attente de pression mémoire. Associez‑le au taux de swap‑out.

5) Pourquoi la VM paraît‑elle avoir beaucoup de mémoire dans l’UI de l’hyperviseur, alors que l’invité swappe ?

Parce que les UIs affichent souvent la mémoire maximale configurée, pas la mémoire effective actuelle après ballooning. Faites confiance à la vue de l’invité et aux stats du balloon.

6) Baisser vm.swappiness résout‑il les problèmes de ballooning ?

Ça peut réduire la propension du noyau à swapper, mais cela ne crée pas de RAM. Si le ballooning retire trop de mémoire, vous aurez toujours des douleurs de reclamation — juste dans un autre ordre.

7) zram est‑il un bon défaut dans les VMs ?

Ça dépend. zram échange I/O disque contre CPU. Sur des systèmes légers en CPU mais contendus en stockage, c’est gagnant. Sur des workloads CPU‑bound (ou quand le steal CPU est élevé), ça peut empirer la latence tail.

8) Comment dimensionner le swap dans une VM qui ne doit pas thrash ?

Petit : suffisant pour absorber de brèves pointes (ou capturer un dump), pas assez pour laisser la VM « survivre » dans un état dégradé permanent. Ensuite, utilisez des caps de swap cgroup pour les gros coupables connus.

9) Quelles bonnes pratiques pour les bases de données face au ballooning ?

Ne les balloonez pas. Réservez la mémoire. Si vous devez ballooner, fixez un plancher élevé et assurez‑vous que les paramètres mémoire de la base (buffers, caches) ne supposent pas que le maximum est toujours présent.

10) Pourquoi tout devient lent même si un seul service mange la mémoire ?

Parce que la reclamation globale et l’I/O de swap affectent tout le système : le CPU est consommé par la reclamation, les files d’I/O se remplissent, et la latence se propage. Contenez l’usage mémoire au niveau service.

Conclusion : prochaines étapes pratiques

Si Ubuntu 24.04 dans une VM vous surprend avec des tempêtes de swap causées par le ballooning, le remède n’est pas un sysctl magique. C’est un contrat mémoire explicite et une application des règles au bon niveau.

  1. Dans les 30 minutes : exécutez le playbook de diagnostic rapide, capturez free, vmstat, PSI, et iostat. Prouvez si du swap est actif et si le ballooning est en cause.
  2. Dans la journée : classifiez les VMs en garanti/élastique/best‑effort et ajustez les minimums de ballooning ou désactivez le ballooning pour les tiers garantis.
  3. Dans la semaine : ajoutez des limites cgroup v2 pour la poignée de services capables de dominer la mémoire, et plafonnez le swap pour ces services quand le « fail fast » vaut mieux que le « slow forever ».
  4. Toujours : alertez sur PSI memory full et sur le swap‑out soutenu. Traitez les tempêtes de swap comme une classe d’incident, pas comme un mystère.

Le ballooning est acceptable quand vous pouvez tolérer les surprises. La production ne peut généralement pas. Fixez des limites comme si vous les pensiez sérieusement, et votre stockage arrêtera de crier à 3 h du matin.

← Précédent
Réseau hôte Docker : risques, quand l’utiliser et comment limiter les dégâts
Suivant →
Un clic de phishing : comment les entreprises deviennent la Une

Laisser un commentaire