À 02:17, votre graphique fait la scène classique d’un film d’horreur : des pics de latence, le « steal » CPU semble normal, mais l’application commence à délaisser. Les disques ne sont pas pleins. Le réseau est ennuyeux. Pourtant la machine donne l’impression de patauger dans du ciment. Vous vous connectez en SSH et voyez de l’activité de swap et une pile de pages sales. Rien n’est techniquement « tombé », et pourtant tout est inutilisable.
C’est là que de minuscules réglages du noyau cessent d’être des détails triviaux et deviennent un volant de direction. Ubuntu 24.04 est livré avec des valeurs par défaut raisonnables pour des systèmes à usage général. En production, c’est rarement du général. Si votre charge est gourmande en mémoire, sujette à des rafales d’E/S ou tourne sur des volumes cloud au comportement particulier, vm.swappiness et les réglages vm.dirty* font partie des rares petits ajustements qui peuvent vraiment changer les résultats.
1. Le modèle mental : ce que ces réglages contrôlent vraiment
Le swapping n’est pas juste « plus de RAM » ; c’est « j’ai choisi une victime »
La gestion mémoire Linux est une négociation entre la mémoire anonyme (tas, piles, allocations temporaires) et la mémoire adossée à des fichiers (page cache, fichiers mmappés). Quand vous voyez de l’activité de swap, cela ne signifie pas nécessairement que vous êtes « à court de RAM ». Cela signifie que le noyau a décidé que certaines pages anonymes valent moins que le maintien d’autres pages en mémoire.
vm.swappiness n’est pas un simple interrupteur marche/arrêt. C’est un signal de préférence : à quel point le noyau doit-il être agressif pour récupérer la mémoire anonyme en la swapant versus récupérer le cache de fichiers (abandonner des pages de cache propres). Des valeurs plus élevées encouragent plus de swapping tôt ; des valeurs plus basses favorisent garder la mémoire anonyme en RAM et sacrifier d’abord le cache.
Ce biais compte parce que le swapping a un mode d’échec brutal : la latence devient non linéaire. Un système peut sembler parfaitement bien fonctionner puis devenir subitement non réactif lorsqu’il entre dans un comportement soutenu de swap-in/swap-out. C’est la tempête de swap : pas un unique gros swap, mais un cycle répétitif où l’ensemble de travail est plus grand que la RAM effective et le noyau continue d’expulser ce dont le processus aura de nouveau besoin bientôt.
Les pages sales sont une « dette IO » qui finit par être exigible
Quand une application écrit dans un fichier, le noyau marque souvent des pages comme sales en RAM et renvoie rapidement. C’est une fonctionnalité de performance : regrouper les écritures coûte moins que d’émettre de petites E/S synchrones. La dette, c’est que ces pages sales doivent être vidées sur le stockage plus tard. Les réglages vm.dirty* décident combien cette dette peut être importante, à quelle vitesse elle doit être remboursée et à quel point le noyau doit throttler les écrivains quand le registre paraît inquiétant.
Deux ratios dominent généralement la conversation :
vm.dirty_background_ratio: quand la mémoire sale dépasse ce pourcentage, l’écriture en arrière-plan commence.vm.dirty_ratio: quand la mémoire sale dépasse ce pourcentage, les processus effectuant des écritures sont throttlés (ils aident effectivement à vider).
Il existe aussi des versions basées sur des octets (vm.dirty_background_bytes, vm.dirty_bytes) qui remplacent les ratios lorsqu’elles sont définies. En production, les réglages en octets sont souvent plus sûrs car les ratios évoluent avec la RAM, et les tailles modernes de RAM rendent « pourcentage de RAM » dangereusement grand en termes d’octets sales. Avec 256 Go de RAM, 20 % de dirty, c’est beaucoup de dette IO.
Ces réglages n’« accélèrent » pas les disques. Ils sculptent la douleur
Aucun sysctl ne rend un stockage lent plus rapide. Ce que ces réglages font, c’est décider quand vous payez le coût de la pression mémoire et du writeback, et si vous le payez par un travail d’arrière-plan gérable ou par un blocage catastrophique au premier plan. Votre but est la prévisibilité ennuyeuse :
- Swapper uniquement quand c’est vraiment moins nuisible que de vider le cache.
- Renvoyer les données sales de façon régulière pour ne pas atteindre une falaise.
- Throttler les écrivains avant que le système ne devienne une prise d’otages.
Une citation qui vieillit bien en exploitation : L’espoir n’est pas une stratégie.
(idée paraphrasée, attribuée au général Gordon R. Sullivan). Les valeurs par défaut du noyau sont de l’espoir. La production est de l’évidence.
2. Faits intéressants et un peu d’histoire (parce que les valeurs par défaut ont une genèse)
- Fait 1 : Le page cache n’est pas de la « mémoire gaspillée ». Linux remplira volontiers la RAM avec du cache et la libérera instantanément quand les applications auront besoin de mémoire. La confusion vient d’anciens outils et de vieux modèles mentaux.
- Fait 2 : Les premiers noyaux Linux avaient des heuristiques de swap très différentes ; le comportement de swapping a été remanié à plusieurs reprises à mesure que le stockage et les tailles de RAM évoluaient.
- Fait 3 : Des ratios comme
dirty_ratioavaient plus de sens quand « beaucoup de RAM » signifiait quelques gigaoctets. Aujourd’hui, des limites basées sur un pourcentage peuvent se traduire par des dizaines de gigaoctets de données sales — des rafales d’E/S énormes plus tard. - Fait 4 : Le sous-système de writeback est conçu pour lisser les E/S, mais il ne peut lisser que ce que le stockage peut supporter. Des applications rafales sur des disques cloud rafales ont des conséquences rafales.
- Fait 5 : Le noyau a plusieurs mécanismes de reclaim : abandon de page cache propre, écriture des pages sales, compactage mémoire et swapping. Ils interagissent ; régler un seul bouton peut changer le chemin choisi.
- Fait 6 : Le swap sur SSD est devenu pratique, puis courant, ce qui a changé l’équation de coût. Le swap est toujours plus lent que la RAM, mais ce n’est plus « la mort instantanée » partout.
- Fait 7 : Les cgroups et les conteneurs ont changé la notion de « pression mémoire ». Le swapping peut se produire à cause de limites de cgroup même si l’hôte a beaucoup de RAM.
- Fait 8 : Les réglages « dirty » affectent aussi combien de temps les données peuvent rester en RAM avant d’être écrites — important pour les attentes de durabilité et pour la sévérité de la récupération après crash.
3. vm.swappiness : quand échanger sur disque est intelligent et quand c’est impoli
Ce que swappiness influence réellement
vm.swappiness varie de 0 à 200 sur les noyaux modernes (la plupart des distributions utilisent la convention 0–100, mais le noyau autorise 200). Les valeurs par défaut d’Ubuntu sont généralement autour de 60. C’est un compromis : un peu de swapping est acceptable si cela préserve le cache et le débit global.
Voici l’essentiel : swappiness ne dit pas « ne jamais swapper ». Il dit « à quel point le noyau doit-il s’efforcer d’éviter le swapping comparé au fait de récupérer le cache ». Si vous le réglez trop bas, le noyau peut abandonner agressivement le cache et vous pouvez vous retrouver avec plus de lectures disque (misses du cache) et une performance pire pour les services lourds en E/S. Si vous le réglez trop haut, vous pouvez swapper de la mémoire qui sera à nouveau nécessaire bientôt, et la latence devient en dents de scie.
Quand une swappiness plus basse est généralement correcte
- Services sensibles à la latence (serveurs API, systèmes interactifs) où des pauses rares et longues sont pires qu’une I/O soutenue légèrement plus élevée.
- Hôtes avec beaucoup de RAM par rapport à l’ensemble de travail, où le swapping indique de mauvaises heuristiques plutôt qu’une nécessité.
- Systèmes où le swap est lent (swap réseau, hyperviseurs surcommités, ou disques cloud bas de gamme sous pression de crédits).
Quand une swappiness plus élevée peut être rationnelle
- Charges mixtes où garder le cache de fichiers chaud est important (machines de compilation, serveurs d’artefacts, bases de données majoritairement en lecture qui tirent avantage du cache OS).
- Surréservation mémoire avec pages froides connues (certains JVM, certains caches, certains jobs batch) où swapper des pages anonymes inactives peut être moins nuisible que de thrash le page cache.
- Quand le swap est assez rapide (NVMe, bons SSD) et que vous échangez du débit contre un peu plus d’I/O de swap sans dégrader les latences extrêmes.
Deux plages cibles réalistes
Conseils opinionés qui tiennent généralement en production :
- Serveurs généraux : 20–60. Commencez à 30 si vous hésitez et que le swap est activé.
- Machines sensibles à la latence : 1–10, mais seulement après avoir confirmé que vous ne comptez pas sur le swap comme filet de sécurité.
Une swappiness de 0 est souvent mal comprise. Elle ne signifie pas « swap désactivé ». Elle signifie « éviter le swap autant que possible », mais sous forte pression, le swapping peut toujours arriver. Si vous voulez vraiment aucun swap, désactivez swap (en acceptant ce que cela implique : l’OOM killer devient votre instrument brutal).
Blague #1 : Mettre vm.swappiness=1 c’est comme coller un post-it « s’il te plaît sois gentil » au noyau. Parfois il écoute ; parfois il a une journée.
4. Paramètres vm.dirty : writeback, throttling et pourquoi « buffers » n’est pas gratuit
Rencontrez le quatuor dirty
L’ensemble couramment ajusté :
vm.dirty_background_ratio/vm.dirty_background_bytes: démarrer la vidange en arrière-plan quand les pages sales dépassent ce seuil.vm.dirty_ratio/vm.dirty_bytes: throttler les écrivains au premier plan quand les pages sales dépassent ce seuil.vm.dirty_expire_centisecs: combien de temps les données sales peuvent rester avant d’être considérées assez vieilles pour être écrites (en 1/100 s).vm.dirty_writeback_centisecs: à quelle fréquence le noyau réveille les threads de flusher pour écrire (en 1/100 s).
Les ratios sont des pourcentages de la mémoire totale. Les octets sont des seuils absolus. Si vous définissez les octets, le ratio est effectivement ignoré pour ce côté. Le réglage en octets est généralement plus prévisible entre types d’instances et évolutions de RAM.
Le mode d’échec que vous essayez d’éviter : la falaise de writeback
Si vos seuils de dirty sont élevés, le noyau peut accumuler une énorme quantité de données sales en RAM, puis décider soudainement de tout vider. Cela peut saturer votre stockage, déclencher la mise en file d’attente des E/S et bloquer les écritures. Si votre application écrit via I/O tamponnée (comme la plupart), le blocage apparaît comme des processus bloqués en état D et une attente d’E/S élevée. Les utilisateurs appellent ça « le système a gelé ». Les ingénieurs disent « le throttling de writeback a fait son travail, juste pas de façon agréable ».
Sur des volumes cloud, la falaise est encore plus drôle parce que le débit de base et les crédits de rafale peuvent varier dans le temps. Vous pouvez vous « en sortir » avec des ratios sales élevés pendant les rafales puis être puni lorsque le volume revient à son débit de base. Ça paraît aléatoire jusqu’à ce que vous vous rappeliez que le stockage est littéralement un compte bancaire.
Choisir ratios vs octets
Utilisez des ratios quand :
- Vous gérez une flotte assez uniforme avec des tailles de RAM similaires.
- Votre enveloppe de performance évolue proportionnellement avec la RAM et le stockage.
- Vous voulez des calculs mentaux simples et acceptez une certaine variabilité.
Utilisez des octets quand :
- Les tailles de RAM varient largement (commun dans les groupes autoscalés).
- Le débit de stockage est la vraie contrainte et ne suit pas la RAM.
- Vous voulez plafonner la dette IO à quelque chose que votre stockage peut vider de façon prévisible.
Points de départ concrets qui se comportent généralement
Ce ne sont pas des valeurs magiques, mais elles sont moins susceptibles de produire l’effet falaise que la méthode « augmentons dirty_ratio ».
- Pour des VM SSD polyvalentes : définir
dirty_background_bytesentre 256–1024 Mo etdirty_bytesentre 1–4 Go, selon la bande passante de stockage et la rafale d’écriture. - Pour services à forte écriture sur disques modestes : seuils plus petits (background 128–512 Mo, max 512 Mo–2 Go) et un writeback plus fréquent réduisent les pics.
- Pour nœuds grande mémoire : les octets battent presque toujours les ratios à moins que le stockage ne suive la RAM (rare hors machines très chères).
Intervals expire et writeback : les contrôles « à quel point lissage est lissé »
dirty_writeback_centisecs définit à quelle fréquence le writeback en arrière-plan démarre. Des intervalles plus courts peuvent signifier un writeback plus régulier au prix d’une vidange plus fréquente. dirty_expire_centisecs traite de combien de temps les données peuvent rester sales avant d’être considérées comme assez vieilles pour être poussées.
Pour la plupart des serveurs, les valeurs par défaut conviennent. Mais si vous observez un comportement périodique « toutes les N secondes le monde pause », ces paramètres sont suspects, surtout combinés à des ratios dirty élevés. N’allez pas trop loin. Petits changements, mesurer, répéter.
Blague #2 : Les pages sales sont comme la vaisselle dans l’évier : vous pouvez les empiler incroyablement haut, mais tôt ou tard quelqu’un devra en affronter les conséquences.
5. Plan de diagnostic rapide (premier/deuxième/troisième)
Premier : décidez si vous souffrez de pression mémoire ou de pression writeback
- Signes de pression mémoire : augmentation de
pgscan/pgsteal, reclaim fréquent, swap in/out croissants, défauts de page majeurs,kswapdoccupé. - Signes de pression writeback : de nombreuses tâches bloquées en état
D, attente d’E/S élevée, pages sales en grand nombre,balance_dirty_pagesapparaît dans les stacks (si vous échantillonnez), utilisation de stockage saturée.
Second : localisez la couche goulot en 5 minutes
- Le swap est-il réellement utilisé ? Si oui, est-ce un filet de fond constant ou une tempête ?
- Les pages sales augmentent-elles ? Si oui, atteignez-vous le seuil de throttling dirty ?
- Le stockage est-il saturé ? Si oui, est-ce le débit, les IOPS, la profondeur de file ou la latence ?
- Est-ce par cgroup/conteneur ? Sur un hôte avec des conteneurs, vérifiez les contraintes mémoire et IO des cgroups.
Troisième : choisissez le bon levier
- Tempête de swap : réduisez l’ensemble de travail, ajoutez de la RAM, ajustez swappiness, corrigez les fuites mémoire, envisagez zswap/zram seulement en connaissance de cause.
- Falaise de writeback : plafonnez les dirty bytes, baissez les ratios dirty, lissez les intervalles de writeback, et corrigez le goulot stockage (souvent la vraie réponse).
- Les deux à la fois : probablement une application effectuant des écritures tamponnées intensives pendant que la mémoire est tendue. Le tuning aide, mais la planification de capacité corrige.
6. Tâches pratiques (commandes + signification des sorties + décisions)
Tâche 1 : Confirmer la swappiness et les réglages dirty courants
cr0x@server:~$ sysctl vm.swappiness vm.dirty_ratio vm.dirty_background_ratio vm.dirty_bytes vm.dirty_background_bytes vm.dirty_expire_centisecs vm.dirty_writeback_centisecs
vm.swappiness = 60
vm.dirty_ratio = 20
vm.dirty_background_ratio = 10
vm.dirty_bytes = 0
vm.dirty_background_bytes = 0
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500
Ce que cela signifie : les ratios sont actifs (les octets sont à zéro). Les données sales peuvent rester ~30 secondes avant d’être considérées comme anciennes (3000 centisecs). Le writeback se réveille toutes les 5 secondes (500 centisecs).
Décision : Si la RAM est importante et le stockage modeste, envisagez de passer à des limites dirty en octets pour éviter de grosses rafales.
Tâche 2 : Vérifier si le swap est activé et de quel type
cr0x@server:~$ swapon --show --bytes
NAME TYPE SIZE USED PRIO
/swap.img file 8589934592 268435456 -2
Ce que cela signifie : swapfile de 8 GiB, ~256 MiB utilisés. Ce n’est pas automatiquement mauvais ; tout dépend des tendances.
Décision : Si l’utilisation du swap augmente régulièrement sous charge et ne redescend jamais, vous dépassez probablement l’ensemble de travail ou vous avez une fuite mémoire.
Tâche 3 : Vérifier rapidement la pression mémoire (y compris tendances de swap)
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 31Gi 18Gi 1.2Gi 1.0Gi 12Gi 9.5Gi
Swap: 8.0Gi 256Mi 7.8Gi
Ce que cela signifie : « available » est votre amie ; elle estime la mémoire qui peut être récupérée sans swap massif. Un faible « free » seul n’a pas de sens sur Linux.
Décision : Si available s’effondre et que le swap augmente sous charge normale, vous avez besoin de capacité ou d’une réduction de l’ensemble de travail, pas d’un sysctl magique.
Tâche 4 : Voir l’activité de swap réelle dans le temps
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
2 0 262144 1265000 120000 9500000 0 0 120 180 600 1200 12 4 82 2 0
3 0 262144 1180000 120000 9440000 0 0 100 210 620 1300 14 4 80 2 0
4 1 310000 900000 119000 9300000 2048 4096 90 5000 800 2000 18 6 60 16 0
2 2 420000 600000 118000 9100000 4096 8192 60 9000 1000 2600 20 7 45 28 0
1 2 520000 500000 118000 9000000 4096 8192 40 12000 1100 2800 22 7 40 31 0
Ce que cela signifie : si/so (swap-in/out) en hausse indique du swapping actif. Une augmentation de b indique des processus bloqués (souvent sur I/O). Une hausse de wa pointe vers l’attente d’E/S.
Décision : Si vous voyez un swap-in soutenu (si) pendant le trafic utilisateur, réduire la swappiness peut aider seulement si le système swappe « inutilement ». Si l’ensemble de travail est trop grand, le tuning ne vous sauvera pas.
Tâche 5 : Identifier les plus gros consommateurs de swap
cr0x@server:~$ sudo smem -rs swap -k | head -n 8
PID User Command Swap USS PSS RSS
14231 app /usr/bin/java -jar service.jar 512000 420000 600000 1300000
5123 postgres /usr/lib/postgresql/16/bin/... 128000 300000 380000 700000
2211 root /usr/bin/containerd 24000 35000 42000 90000
1987 root /usr/lib/systemd/systemd 2000 8000 12000 25000
Ce que cela signifie : Quels processus sont réellement swapés, pas seulement volumineux.
Décision : Si un processus critique en latence a du swap significatif, envisagez des ajustements mémoire dans l’application, ajouter de la RAM ou réduire la swappiness. Si seuls des daemons vraiment inactifs sont swapés, pas de panique.
Tâche 6 : Vérifier les niveaux de pages sales et l’activité de writeback
cr0x@server:~$ egrep 'Dirty|Writeback|MemTotal' /proc/meminfo
MemTotal: 32734064 kB
Dirty: 184320 kB
Writeback: 16384 kB
WritebackTmp: 0 kB
Ce que cela signifie : Dirty est actuellement faible (~180 MiB). Writeback est actif mais modeste.
Décision : Si Dirty monte à plusieurs gigaoctets et y reste, vous accumulez probablement une dette IO plus vite que le stockage ne peut la vider.
Tâche 7 : Vérifier les seuils dirty globaux du noyau (calculés)
cr0x@server:~$ cat /proc/sys/vm/dirty_background_ratio /proc/sys/vm/dirty_ratio
10
20
Ce que cela signifie : La vidange en arrière-plan commence à 10 % de la mémoire ; le throttling à 20 %.
Décision : Sur des systèmes avec beaucoup de RAM, c’est souvent trop élevé en valeur absolue. Envisagez des limites en octets.
Tâche 8 : Mesurer l’I/O bloquée et la saturation disque
cr0x@server:~$ iostat -xz 1 3
Linux 6.8.0 (server) 12/30/2025 _x86_64_ (8 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
14.20 0.00 5.10 18.40 0.00 62.30
Device r/s rkB/s rrqm/s %rrqm r_await w/s wkB/s w_await aqu-sz %util
nvme0n1 120.0 5200.0 2.0 1.6 4.2 980.0 64000.0 22.5 7.8 99.0
Ce que cela signifie : Le disque est saturé (%util ~99) et la latence d’écriture (w_await) est élevée. C’est cohérent avec le throttling de writeback et/ou de lourdes écritures.
Décision : Le tuning des paramètres dirty peut lisser les rafales, mais si le disque est saturé en permanence, il vous faut un stockage meilleur, moins de volume d’écriture, ou optimiser au niveau applicatif (batching, compression).
Tâche 9 : Rechercher des tâches bloquées en sleep I/O non interruptible
cr0x@server:~$ ps -eo state,pid,comm,wchan:32 --sort=state | head -n 15
D 9182 postgres io_schedule
D 14231 java balance_dirty_pages
D 7701 rsyslogd ext4_da_writepages
R 2109 sshd -
S 1987 systemd ep_poll
S 2211 containerd ep_poll
Ce que cela signifie : Les tâches en état D sont bloquées, typiquement sur I/O. Voir balance_dirty_pages est un indice fort que le throttling dirty est actif.
Décision : Si beaucoup de workers restent dans balance_dirty_pages, réduisez les limites dirty et/ou corrigez le débit du stockage. Évaluez aussi si votre application fait de grosses écritures tamponnées sans logique de backpressure.
Tâche 10 : Vérifier les limites mémoire des cgroups (les conteneurs en pâtissent)
cr0x@server:~$ cat /sys/fs/cgroup/memory.max
max
Ce que cela signifie : Cet hôte (ou ce cgroup courant) n’est pas limité en mémoire.
Décision : Si vous voyez un nombre au lieu de max, le comportement de swapping peut être déclenché par la pression du cgroup même si la machine paraît avoir de la marge.
Tâche 11 : Appliquer un réglage temporaire en toute sécurité (runtime seulement)
cr0x@server:~$ sudo sysctl -w vm.swappiness=30
vm.swappiness = 30
Ce que cela signifie : Vous avez changé le paramètre du noyau en cours d’exécution. Après reboot, cela reviendra à la valeur précédente sauf si vous le persistez.
Décision : Si les tempêtes de swap diminuent et que les misses de cache n’explosent pas, envisagez de persister. Si rien ne change, ne le faites pas en mode cargo-cult — cherchez ailleurs.
Tâche 12 : Passer le tuning dirty à des caps en octets (runtime seulement)
cr0x@server:~$ sudo sysctl -w vm.dirty_background_bytes=536870912 vm.dirty_bytes=2147483648
vm.dirty_background_bytes = 536870912
vm.dirty_bytes = 2147483648
Ce que cela signifie : La vidange en arrière-plan commence à 512 MiB de dirty, le throttling à 2 GiB de dirty — indépendamment de la taille de la RAM.
Décision : Si cela lisse l’attente d’E/S et réduit les blocages « writeback cliff », persistez. Si votre charge dépend d’un très grand cache d’écriture pour le débit, vous verrez peut-être une baisse des pics ; décidez si vous préférez le pic ou la prévisibilité.
Tâche 13 : Persister les sysctls correctement (et vérifier)
cr0x@server:~$ sudo tee /etc/sysctl.d/99-vm-tuning.conf >/dev/null <<'EOF'
vm.swappiness=30
vm.dirty_background_bytes=536870912
vm.dirty_bytes=2147483648
EOF
cr0x@server:~$ sudo sysctl --system | tail -n 6
* Applying /etc/sysctl.d/99-vm-tuning.conf ...
vm.swappiness = 30
vm.dirty_background_bytes = 536870912
vm.dirty_bytes = 2147483648
Ce que cela signifie : Les réglages sont maintenant persistants et appliqués. La sortie confirme ce qui a été chargé.
Décision : Si sysctl --system montre que vos valeurs sont écrasées plus tard, une autre source (cloud-init, gestion de configuration, agent fournisseur) vous contredit. Trouvez et corrigez la source de vérité.
Tâche 14 : Confirmer que les ratios dirty sont effectivement désactivés lorsque les octets sont définis
cr0x@server:~$ sysctl vm.dirty_ratio vm.dirty_bytes
vm.dirty_ratio = 20
vm.dirty_bytes = 2147483648
Ce que cela signifie : La valeur ratio s’affiche toujours, mais dirty_bytes prend la priorité pour le throttling.
Décision : Laissez les ratios par défaut sauf raison contraire. Les octets sont votre contrôle effectif maintenant.
Tâche 15 : Vérifier les rafales dues à delayed allocation d’ext4 (contexte, pas blâme)
cr0x@server:~$ mount | grep ' on / '
/dev/nvme0n1p2 on / type ext4 (rw,relatime,errors=remount-ro)
Ce que cela signifie : ext4 avec delayed allocation peut regrouper les écritures, ce qui peut amplifier les rafales de writeback selon la charge.
Décision : Ne modifiez pas les options de montage du système de fichiers comme première réponse. Utilisez des caps dirty pour modeler la rafale ; changez le comportement du FS seulement si vous avez une raison mesurée.
7. Profils de réglage opinionés qui ne créent pas d’échecs silencieux
Profil A : « Serveurs plutôt normaux » (web + sidecars + écritures modestes)
Utilisez ceci lorsque vous voulez moins de surprises, pas les chiffres maximums de benchmark.
vm.swappiness=30vm.dirty_background_bytes=268435456(256 MiB)vm.dirty_bytes=1073741824(1 GiB)
Pourquoi : Cela limite la dette dirty. Commence la vidange plus tôt. Permet toujours du buffering pour le débit, mais pas « tamponnons 30 Go parce qu’on peut ».
Profil B : « Écriture-intensive, sensible à la latence » (logs, ingestion, files)
vm.swappiness=10(ou 20 si vous dépendez fortement du cache)vm.dirty_background_bytes=134217728(128 MiB)vm.dirty_bytes=536870912(512 MiB)
Pourquoi : Vous échangez un tamponnage d’écriture maximal contre moins de chutes de latence extrême. Cela réduit la probabilité qu’un flush soudain balaie votre service.
Profil C : « Grandes machines mémoire avec stockage inégal » (le piège classique)
vm.swappiness=20–40selon la chargevm.dirty_background_bytes=536870912(512 MiB)vm.dirty_bytes=2147483648(2 GiB)
Pourquoi : Grande RAM plus disques moyens, c’est la manière de construire accidentellement une machine à dette IO. Les ratios montent avec la RAM, mais les disques ne suivent pas.
Ce qu’il faut éviter (parce que vous serez tenté)
- Ne pas augmenter
dirty_ratiopour « améliorer les performances » sauf si vous êtes sûr que le stockage peut supporter la vidange ultérieure. Vous achetez généralement un gain de benchmark au prix d’une panne en production. - Ne pas désactiver swap aveuglément sur des serveurs à usage général. Vous remplacez un mécanisme de dégradation graduelle par un mécanisme de mort subite.
- Ne pas tuner à l’aveugle. Si vous ne mesurez pas l’attente d’E/S, les niveaux dirty et l’activité de swap, vous réarrangez juste des vibrations du noyau.
8. Trois mini-histoires d’entreprise sorties du terrain
Histoire 1 : L’incident causé par une mauvaise hypothèse
Ils avaient une flotte de serveurs Ubuntu exécutant une API chargée, plus un worker en arrière-plan qui écrivait périodiquement des exportations en lot sur disque. Rien d’exotique. L’équipe a remarqué une utilisation de swap qui s’accumulait sur des semaines et a décidé que le swap était le coupable. La solution fut décisive : désactiver le swap partout. « Le swap est lent ; nous avons suffisamment de RAM. » Une phrase qui a mis fin à de nombreuses rotations d’astreinte paisibles.
Deux jours plus tard, une montée de trafic est arrivée avec une fuite mémoire modeste dans un chemin de code rarement utilisé. La fuite n’était pas énorme, et avec le swap présent, le système aurait continué à fonctionner tant bien que mal pendant que les alertes sonnaient. Sans swap, le noyau n’avait plus qu’un seul outil : l’OOM killer. Sous charge, l’OOM killer a fait ce qu’il sait faire : il a tué un processus qui semblait utiliser beaucoup de mémoire. Ce processus était l’API worker.
L’incident n’était pas dramatique au début. Il était pire : un motif en rolling de défaillances partielles. Des instances sortaient du load balancer, redémarraient, réchauffaient le cache, puis mouraient à nouveau. Les utilisateurs ont vu des erreurs intermittentes. Les ingénieurs ont vu des graphiques CPU « sains » et un sentiment croissant de trahison personnelle.
La mauvaise hypothèse n’était pas « le swap est lent ». Le swap est lent. La mauvaise hypothèse était de croire que le swap sert seulement la performance. Le swap est aussi pour la stabilité — il vous achète du temps pour détecter des fuites et récupérer proprement. Après l’incident, ils ont réactivé le swap et mis une swappiness plus basse. Puis ils ont corrigé la fuite. Le changement le plus important fut culturel : ils ont arrêté de considérer le swap comme une faute morale.
Histoire 2 : L’optimisation qui a mal tourné
Une équipe plateforme data avait des nœuds grande mémoire et une ingestion très écriture-intensive. Quelqu’un a lu que l’augmentation des ratios dirty pouvait améliorer le débit parce que le noyau pouvait regrouper plus d’écritures. Ils ont augmenté vm.dirty_ratio et vm.dirty_background_ratio substantiellement. Dans un test synthétique, le débit avait l’air excellent. Les dashboards souriaient. La PR a été fusionnée rapidement.
En production, la charge n’était pas un flux constant. Elle était en rafales : pics d’écritures suivis de périodes calmes. Avec des ratios dirty élevés, le système a tamponné joyeusement de grosses rafales en RAM. Puis la période calme est arrivée et le noyau a commencé à vider une montagne de données sales. Les flushes furent assez importants pour saturer le stockage, ce qui augmenta la latence d’E/S pour tout le reste : opérations méta, lectures, même petites écritures d’autres services.
Les utilisateurs ont ressenti le problème comme des « blocages aléatoires ». Les blocages coïncidaient avec les cycles de flush, mais seulement si vous graphiiez la mémoire dirty et la latence d’E/S sur le même axe. La première réponse fut de blâmer l’application. La deuxième fut de blâmer le fournisseur cloud. La troisième — finalement — fut d’admettre que le noyau faisait exactement ce qu’on lui demandait, et que l’optimisation était réglée pour un benchmark, pas pour une flotte rafaleuse.
La solution fut banale : passer à des limites dirty en octets qui reflétaient ce que le stockage pouvait réellement vider sans drame. Le débit a légèrement baissé pendant les rafales les plus agressives. La latence tail s’est grandement améliorée. Tout le monde a prétendu que c’était prévu, ce qui est aussi ennuyeux et donc acceptable.
Histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une équipe liée à la finance exploitait des hôtes Ubuntu 24.04 qui traitaient la clôture de fin de mois. La charge était prévisible : écritures intensives pendant quelques heures, puis calme. Ils ne couraient pas après la performance maximale ; ils cherchaient « ne pas me réveiller ». Leur pratique était douloureusement peu glamour : chaque changement de tuning noyau nécessitait un déploiement canari, un jeu de mesures avant/après et un plan de rollback.
Ils avaient standardisé des caps dirty en octets et une swappiness modérée. Ils avaient aussi des dashboards pour la mémoire dirty, la latence d’E/S et les taux swap-in/out. Pas parce que c’est fun, mais parce que ça évite les débats basés sur les impressions.
Un mois, un changement de backend stockage a introduit une latence d’écriture légèrement plus élevée. Rien de catastrophique, juste plus lent. Lors du premier run de traitement intensif, leurs métriques ont montré une montée plus rapide des pages sales que d’habitude et le throttling en foreground s’est déclenché plus tôt. Mais parce que leurs caps dirty étaient conservateurs, le système a dégradé de façon graduelle : le traitement a pris plus de temps, mais les hôtes sont restés réactifs, et rien n’a dégénéré en tempête de blocage.
L’équipe a utilisé les preuves pour faire reculer le changement de stockage et ajusté temporairement la planification des jobs. Pas d’héroïsme, pas d’archéologie du noyau à 3h du matin. La pratique correcte n’était pas un sysctl magique ; c’était traiter les sysctls comme une configuration de production avec observabilité et contrôle des changements.
9. Erreurs courantes : symptôme → cause racine → correction
1) Symptôme : « Le swap est utilisé alors qu’il reste de la RAM libre »
Cause racine : « free » n’est pas le bon indicateur. Linux utilise la RAM pour le cache ; les décisions de swap dépendent du coût de reclaim, pas des « MB libres ». Aussi, des pages anonymes froides peuvent être swapées pour garder le cache chaud.
Correction : Regardez available dans free, suivez swap-in/out avec vmstat. Si le swap-in est proche de zéro et que la performance est correcte, ne faites rien. Si le swap-in monte sous charge, réduisez l’ensemble de travail ou baissez la swappiness prudemment.
2) Symptôme : blocages périodiques de 10–60 secondes ; beaucoup de processus en état D
Cause racine : Falaise de writeback : trop de pages sales s’accumulent, puis un gros flush saturant le stockage throttle les écrivains.
Correction : Définissez vm.dirty_background_bytes et vm.dirty_bytes à des caps sensés ; vérifiez avec /proc/meminfo et des outils de latence E/S (iostat). Envisagez de réduire modérément les intervalles expire/writeback si les flushes sont trop bosselés.
3) Symptôme : forte attente d’E/S mais faible débit disque
Cause racine : Stockage lié à la latence (IOPS limité, mise en file, throttling, ou voisin bruit). Le throttling dirty peut l’amplifier parce que les écrivains attendent la complétion du writeback.
Correction : Utilisez iostat -xz pour vérifier await et la taille de la file ; réduisez les caps dirty pour limiter l’explosion de la file ; traitez les limites du stockage (volume avec plus d’IOPS, NVMe local, ou réduire les écritures synchrones).
4) Symptôme : le swapping provoque des pics de latence tail, mais le swap total utilisé est « petit »
Cause racine : Même de petits taux de swap-in peuvent nuire s’ils touchent des pages chaudes pendant le pic. Les charges sensibles à la latence détestent le swap-in plus que la perte de cache.
Correction : Baissez la swappiness (ex. 10–30), vérifiez que l’application ne fuit pas la mémoire, et assurez-vous que le périphérique de swap n’est pas lent. Envisagez d’isoler/pinner les services critiques via des cgroups plutôt que des hacks globaux.
5) Symptôme : après avoir réglé dirty bytes, le débit a chuté et le CPU a augmenté
Cause racine : Vous avez trop réduit le buffering, provoquant des writebacks plus fréquents et plus petits et donc plus de surcoût, ou vous avez forcé le throttling au premier plan trop souvent.
Correction : Augmentez légèrement dirty_bytes (ex. de 512 MiB à 1 GiB) et re-mesurez. Ne revenez pas aux ratios énormes ; visez les plus petits caps qui évitent les blocages.
6) Symptôme : « Les paramètres disparaissent » après reboot
Cause racine : Vous avez changé seulement le runtime sysctl, ou un autre composant écrase les sysctls au démarrage.
Correction : Mettez les paramètres dans /etc/sysctl.d/, exécutez sysctl --system, et inspectez les logs de démarrage ou la gestion de configuration pour trouver l’override.
7) Symptôme : un conteneur swappe beaucoup alors que l’hôte semble correct
Cause racine : Les limites mémoire de cgroup (et possiblement les limites de swap) déclenchent le reclaim dans le scope du conteneur.
Correction : Inspectez memory.max du cgroup, les requests/limits mémoire du conteneur et le dimensionnement de la charge. La swappiness globale ne résoudra pas une limite de conteneur trop stricte.
10. Checklists / plan étape par étape
Étape par étape : workflow de tuning sûr pour la production
- Écrivez le symptôme en termes opérationnels : « spikes p99 pendant les écritures batch », « hôtes gelés 30 secondes », « swap-in augmente après un déploiement ». Si vous ne pouvez pas le formuler, vous ne pouvez pas le valider.
- Capturez les baselines : swappiness/réglages dirty, utilisation swap, mémoire dirty, latence E/S et tâches bloquées.
- Prouvez quel type de pression domine : mémoire vs writeback vs saturation brute du stockage.
- Changez une dimension à la fois : swappiness ou limites dirty, pas les deux, sauf si vous savez déjà que les deux contribuent.
- Utilisez d’abord sysctl runtime : validez l’impact sous la charge réelle sans vous engager.
- Déploiement canari : appliquez à un petit sous-ensemble ; comparez sous charges identiques.
- Persistez via sysctl.d : conservez un fichier autoritaire par rôle d’hôte ; évitez les « réglages mystères ».
- Validation après reboot : confirmez qu’après redémarrage les réglages restent et que le comportement correspond.
- Documentez le pourquoi : incluez la métrique ciblée et le résultat observé.
Checklist : à quoi ressemble un bon résultat après tuning
- Swap-in/out proche de zéro pendant le trafic normal (sauf raison connue).
- La mémoire dirty monte et redescend en douceur, pas en scie avec de longs plateaux.
- La latence E/S ne pique pas périodiquement en orbite pendant les flushs background.
- Peu ou pas de threads applicatifs bloqués en état
Dlongtemps. - Le débit est acceptable et la latence tail est stable.
Checklist : plan de rollback
- Conservez le contenu du dernier fichier sysctl connu bon dans l’historique de la gestion de configuration.
- Ayez une commande one-liner pour revenir aux réglages runtime (
sysctl -wavec les anciennes valeurs). - Sachez quelles courbes doivent s’améliorer en quelques minutes (dirty/IO wait) versus en heures (tendances swap, comportement du cache).
11. FAQ
1) Dois-je mettre vm.swappiness=1 sur tous les serveurs ?
Non. Sur des services sensibles à la latence, cela peut être raisonnable. Sur des serveurs lourds en I/O qui tirent avantage du cache, cela peut se retourner contre vous en vidant trop agressivement le cache. Commencez autour de 20–30 et mesurez.
2) L’utilisation du swap est-elle toujours mauvaise ?
L’activité de swap pendant les pics est souvent mauvaise. De petites quantités de swap utilisées peuvent être acceptables si ces pages sont vraiment froides et que le swap-in reste proche de zéro.
3) Qu’est-ce qui est mieux : ratios dirty ou octets dirty ?
Les octets dirty sont plus prévisibles entre machines avec des tailles de RAM variées et généralement plus sûrs sur des machines à grande mémoire. Les ratios sont plus simples mais peuvent évoluer vers des arriérés dirty absurdes sur des serveurs modernes.
4) Si je plafonne les dirty bytes, vais-je perdre en performance ?
Vous pouvez perdre du débit de write buffering lors des rafales. Vous gagnez souvent en stabilité et en latence tail plus basse. En production, ce compromis est généralement le bon choix.
5) Ces réglages ont-ils de l’importance pour les bases de données ?
Parfois. Les bases de données avec leur propre buffering et leurs patterns WAL se souciant plus du scheduler I/O, du système de fichiers et du stockage. Mais le writeback dirty peut toujours affecter les tâches background, les logs et tous les chemins I/O tamponnés autour de la base.
6) Pourquoi je vois une forte attente d’E/S alors que le CPU est majoritairement inactif ?
Parce que les threads sont bloqués sur des E/S. Un CPU « idle » ne signifie pas que le système est sain ; cela peut signifier que le CPU n’a rien à faire pendant que tout attend le stockage.
7) Dois-je désactiver le swap pour forcer l’application à échouer vite ?
Seulement si vous voulez vraiment que les OOM kills soient votre principal mécanisme de contrôle et que vous disposez d’une orchestration/stratégie de retry robuste. Pour beaucoup de flottes, le swap est un filet de sécurité qui évite des pannes en cascade lors de pointes mémoire de courte durée.
8) Dois-je tuner dirty_expire_centisecs et dirty_writeback_centisecs ?
Généralement non. Commencez par dirty bytes/ratios. Considérez les intervalles seulement si vous avez des stalls périodiques liés aux flushs et que vous avez confirmé que les limites dirty ne sont pas le problème principal.
9) J’ai changé des sysctls et rien n’a amélioré. Pourquoi ?
Parce que le goulot est souvent le débit/latence du stockage, les patterns d’écriture de l’application ou des fuites mémoire. Les sysctls influencent le comportement en marge ; ils ne créent pas de capacité.
10) Quelle est une manière sûre de tester sans risquer une panne sur toute la flotte ?
Des changements runtime sur une instance canari sous charge représentative, avec des métriques de succès claires : taux swap-in, niveaux dirty, latence E/S et latence des requêtes.
12. Conclusion : prochaines étapes pratiques
Si vos machines Ubuntu 24.04 se bloquent, et que vous observez soit un churn de swap soit un mur de writeback dirty, vous n’avez pas besoin de folklore. Vous avez besoin d’une boucle serrée : observer, plafonner, vérifier.
- Exécutez le diagnostic rapide : est-ce pression swap, pression writeback ou stockage saturé ?
- Si les falaises de writeback sont le problème, passez des seuils dirty en pourcentage à des caps en octets dimensionnés selon la réalité de votre stockage.
- Si les tempêtes de swap sont la cause, baissez la swappiness prudemment et corrigez la vraie cause : ensemble de travail, fuites ou RAM insuffisante.
- Persistez les réglages dans
/etc/sysctl.d/, canarisez-les et vérifiez après reboot.
Ces réglages sont petits. C’est le point. Petites modifications ciblées qui transforment 02:17 en une nuit normale.