Un service web qui ralentit, un worker tué sans message clair ou un serveur qui swap n’a pas forcément épuisé toute la RAM de la machine. Avec systemd, une limite posée sur une unité peut suffire à expliquer le symptôme.
Les cgroups permettent au noyau Linux de compter, limiter et prioriser les ressources d’un groupe de processus. Avant d’ajouter de la mémoire ou de redémarrer au hasard, vérifiez ce que systemd applique au service concerné.

Voir le cgroup d’un service
Sur les distributions récentes, systemd place chaque service dans son propre cgroup. Vous n’avez pas à déplacer des PID à la main pour diagnostiquer une unité classique comme Nginx, PostgreSQL ou un worker applicatif.
Commencez par lire l’état du service et les propriétés liées aux ressources. Remplacez nginx.service par le nom réel de votre unité.
systemctl status nginx.service --no-pager
systemctl show nginx.service -p ControlGroup -p MainPID -p MemoryCurrent -p MemoryMax -p MemoryHigh -p CPUQuotaPerSecUSec
ControlGroup donne le chemin géré par systemd. MemoryCurrent affiche la mémoire comptabilisée pour l’unité au moment de la lecture. Si MemoryMax vaut infinity, systemd n’a pas fixé de plafond mémoire dur sur ce service.
Si vous partez d’un PID, relisez son cgroup depuis /proc. En cgroup v2, vous verrez souvent une ligne du type 0::/system.slice/nginx.service.
pid=$(systemctl show nginx.service -p MainPID --value)
cat /proc/$pid/cgroup
Si MainPID vaut 0, le service n’a pas de processus principal actif. Revenez à systemctl status et à journalctl au lieu de conclure à partir d’un PID vide.
Lire les limites mémoire et CPU
MemoryMax est une limite dure. Si le cgroup atteint ce plafond et que le noyau ne récupère pas assez de mémoire, un processus du groupe peut être tué par l’OOM killer.
MemoryHigh est moins brutal. Le noyau freine les allocations et tente de récupérer de la mémoire quand le cgroup dépasse ce seuil. Pour contenir un service sans le faire tomber au premier pic, c’est souvent un meilleur premier réglage que MemoryMax.
CPUQuota limite le temps CPU disponible pour le service. CPUQuota=25% donne l’équivalent d’un quart de cœur logique. Sur une machine à plusieurs cœurs, CPUQuota=200% autorise jusqu’à deux cœurs de temps CPU.
systemctl show nginx.service \
-p MemoryCurrent -p MemoryMax -p MemoryHigh \
-p CPUUsageNSec -p CPUQuotaPerSecUSec
Ne mélangez pas quota et priorité. Un quota empêche le service de dépasser une quantité de CPU. Une priorité, avec nice ou CPUWeight, arbitre surtout la concurrence quand plusieurs tâches demandent du CPU en même temps.
Trouver l’origine d’une limite
Une limite peut venir du fichier fourni par le paquet, d’un drop-in systemd ou d’un override créé localement. Lisez la configuration complète avant de modifier le service.
systemctl cat nginx.service
systemctl show nginx.service -p FragmentPath -p DropInPaths
Un fichier sous /etc/systemd/system/nginx.service.d/ prend normalement le dessus sur l’unité fournie par le paquet. Évitez de modifier directement un fichier dans /usr/lib/systemd/system/ ou /lib/systemd/system/, car une mise à jour peut l’écraser.
Vérifiez ensuite les symptômes. Un service ralenti peut aussi venir d’une requête SQL lente, d’un disque saturé, d’une file d’attente pleine ou d’une erreur applicative.
journalctl -u nginx.service -b --no-pager
journalctl -k -b | grep -Ei 'oom|out of memory|killed process|memory cgroup'
Si les limites restent à infinity et que le journal noyau ne montre aucun événement mémoire, cherchez ailleurs avant de toucher aux cgroups : logs applicatifs, métriques disque, latence réseau ou consommation réelle du processus.
Tester sans toucher au service
Pour valider une syntaxe ou mesurer l’effet d’une limite, lancez une unité temporaire avec systemd-run. Le test ne modifie pas Nginx, PostgreSQL ou votre service métier.
sudo systemd-run --unit=essai-limite-memoire \
--property=MemoryMax=256M \
--property=CPUQuota=25% \
/usr/bin/bash -c 'sleep 300'
Relisez ensuite les propriétés appliquées. Pour CPUQuota=25%, systemd peut afficher une valeur équivalente à 250ms par seconde.
systemctl show essai-limite-memoire.service \
-p MemoryMax -p CPUQuotaPerSecUSec -p ControlGroup -p ActiveState
systemctl cat essai-limite-memoire.service
Arrêtez l’unité de test dès que vous avez terminé. Avec sleep, l’oubli est sans gravité, mais ce réflexe évite les surprises quand le test lance une vraie commande.
sudo systemctl stop essai-limite-memoire.service
Appliquer un override systemd
Quand les journaux et les mesures confirment qu’une limite a du sens, passez par un override systemd. L’exemple ci-dessous fixe un seuil haut à 800 Mo, un plafond dur à 1 Go et limite le service à l’équivalent d’un cœur CPU.
sudo systemctl edit mon-service.service
Ajoutez seulement les directives nécessaires. Ne copiez pas ces valeurs sur un service de production sans avoir observé sa consommation normale et ses pics.
[Service]
MemoryHigh=800M
MemoryMax=1G
CPUQuota=100%
Rechargez systemd, puis redémarrez le service seulement si l’interruption est acceptable. À distance, gardez une seconde session SSH ouverte quand vous touchez à un composant critique.
sudo systemctl daemon-reload
sudo systemctl restart mon-service.service
systemctl status mon-service.service --no-pager
systemctl show mon-service.service -p MemoryCurrent -p MemoryHigh -p MemoryMax -p CPUQuotaPerSecUSec
Si le service ne démarre plus ou devient trop lent, retirez l’override avec prudence. sudo systemctl revert mon-service.service supprime les overrides locaux de l’unité. Ne l’utilisez pas si le même répertoire contient d’autres réglages à garder.
Contrôles après changement
- Vérifiez l’état avec
systemctl is-active mon-service.service. - Relisez
MemoryCurrent,MemoryHigh,MemoryMaxetCPUQuotaPerSecUSecaprès le redémarrage. - Surveillez
journalctl -u mon-service.service -bet le journal noyau pendant le pic de charge qui posait problème. - Mesurez l’effet côté application : temps de réponse, jobs en retard, files d’attente, erreurs utilisateur.
- Notez la raison du réglage, la date, la valeur retenue et le symptôme corrigé dans votre procédure d’exploitation.
Les cgroups protègent le reste de la machine et rendent les limites visibles. Ils ne corrigent pas une fuite mémoire, une requête trop coûteuse ou un worker mal dimensionné. Si le plafond est atteint, gardez le journal, la charge observée et la valeur configurée pour choisir entre ajuster la limite et corriger l’application.
Pour aller plus loin, la page systemd.resource-control(5) détaille chaque directive. Le guide Nice sous Linux aide à choisir une priorité CPU quand un plafond strict n’est pas adapté.