Skip to content

Better swap linux

Optimisation et Gestion du Swap sous Linux

J'ai toujours eu une petite obsession pour le swap sous linux, je trouve que par défault il est assez mal implémenter et peut entrainer beaucoup de problème. Voici comment je configure le swap sous linux de manière automatique et intelligente.

Note

Ça peut être améliorer surtout pour les système qui n'ont pas beaucoup de ram et avoir quelque chose de plus aggressife en fonction de la conf materiel. Mais j'ai essayé de nombreuse configuration et celle ci est la meilleur pour moi.


Provisionnement et Extension du Swap

Le système surveille dynamiquement l'espace de swap disponible pour s'assurer que les mécanismes de protection (OOMD) disposent de suffisamment de "marge" pour fonctionner.

Détection de l'état actuel

Le playbook Ansible récupère la taille du swap en Go. Si cette valeur est inférieure à un seuil critique (10 Go), une procédure d'extension automatique est déclenchée.

- name: Vérifier la taille actuelle du swap
  shell: free -g | awk 'NR==3 {print $2}'
  register: current_swap_size

- name: Créer et activer le swapfile si swap insuffisant
  when: (current_swap_size.stdout | int) < 10
  block:
    - name: Créer le swapfile (fallocate)
      command: fallocate -l 12G /swapfile
    - name: Sécuriser les permissions
      file: path=/swapfile owner=root group=root mode='0600'
    - name: Formater et activer
      command: "{{ item }}"
      loop:
        - mkswap /swapfile
        - swapon /swapfile

Configuration de systemd-oomd

systemd-oomd est un service qui surveille les groupes de contrôle (cgroups) et tue les processus qui causent une pression excessive sur la RAM ou le Swap. C'est ce qu'on va utiliser pour killer les processus quand le serveur a une fuite mémoire ou alors qu'on l'exploite trop. (Il est plus interressant que l'ancien OOM de linux qui avait tendance a tout tuer d'un coup)

Politique de surveillance (user.slice)

Nous configurons la "slice" utilisateur pour qu'elle soit la cible privilégiée du nettoyage en cas de crise. Cela protège les services critiques du système.

# /etc/systemd/system/user.slice.d/10-oomd-limits.conf
[Slice]
ManagedOOMSwap=kill

Orchestration du démarrage (Désactivation des services par défaut)

Point crucial : Nous désactivons le démarrage automatique standard de systemd-oomd (service et socket). Pourquoi ? Parce qu'au moment du boot, le swapfile n'est pas encore forcément prêt ou stabilisé, et nous voulons appliquer un calcul dynamique avant que le service ne commence à surveiller le système.

- name: Désactiver le démarrage direct de systemd-oomd
  systemd:
    name: "{{ item.name }}"
    enabled: no
  loop:
    - { name: 'systemd-oomd.service' }
    - { name: 'systemd-oomd.socket' }

Le Script de Calcul Dynamique (Smart Limit)

Le cœur du système est le script /usr/local/lib/oomd-update-swap-limit.sh. Il permet d'adapter le seuil de déclenchement (SwapUsedLimit) à la capacité réelle de la machine.

Script Complet

#!/bin/bash
# Adapte SwapUsedLimit au swap réel de la machine au moment du boot.
# Algorithme :
#   - Swap <= 18G → seuil = swap_total - 2G  (marge de sécurité 2G)
#   - Swap >  18G → seuil = 16G  (cap fixe)
# Écrit dans 10-oomd-swap-dynamic.conf qui surcharge 10-oomd-defaults.conf.
set -euo pipefail

SAFETY_MARGIN_KB=$(( 2 * 1024 * 1024 ))   # 2G en kB
MAX_KILL_AT_KB=$(( 16 * 1024 * 1024 ))    # 16G en kB
THRESHOLD_BIG_KB=$(( 18 * 1024 * 1024 ))  # 18G en kB

SWAP_TOTAL_KB=$(awk '/SwapTotal/ {print $2}' /proc/meminfo)

if [[ "${SWAP_TOTAL_KB}" -lt 524288 ]]; then
  echo "[oomd-limit] SwapTotal (${SWAP_TOTAL_KB} kB) trop faible (<512M), oomd non configuré." >&2
  exit 1
fi

# --- Calcul du seuil dynamique ---
if [[ "${SWAP_TOTAL_KB}" -le "${THRESHOLD_BIG_KB}" ]]; then
  # Petit/moyen swap : garder 2G de marge
  KILL_AT_KB=$(( SWAP_TOTAL_KB - SAFETY_MARGIN_KB ))
  ALGO="swap_total - 2G"
else
  # Grand swap : plafonner à 16G
  KILL_AT_KB=${MAX_KILL_AT_KB}
  ALGO="cap fixe 16G"
fi

# Sécurité : ne jamais descendre en dessous de 1G
if [[ "${KILL_AT_KB}" -lt 1048576 ]]; then
  echo "[oomd-limit] Seuil calculé trop bas (${KILL_AT_KB} kB), forçage à 1G." >&2
  KILL_AT_KB=1048576
fi

PCT=$(( (KILL_AT_KB * 100) / SWAP_TOTAL_KB ))
PCT=$(( PCT < 5  ? 5  : PCT ))
PCT=$(( PCT > 95 ? 95 : PCT ))

KILL_AT_GB=$(( KILL_AT_KB / 1024 / 1024 ))
SWAP_TOTAL_GB=$(( SWAP_TOTAL_KB / 1024 / 1024 ))
echo "[oomd-limit] SwapTotal=${SWAP_TOTAL_GB}G → kill à ${KILL_AT_GB}G utilisés → SwapUsedLimit=${PCT}% (algo: ${ALGO})"

cat > /etc/systemd/oomd.conf.d/10-oomd-swap-dynamic.conf <<EOF
[OOM]
SwapUsedLimit=${PCT}%
EOF

systemctl daemon-reload
echo "[oomd-limit] Configuration écrite : SwapUsedLimit=${PCT}%"

Automatisation Post-Boot

Pour garantir que le script ci-dessus est exécuté au bon moment, nous utilisons un service systemd "one-shot" qui temporise le démarrage de la protection.

Service restart-oomd-postboot.service

Ce service attend 2 minutes après le démarrage complet pour laisser le système "respirer" et s'assurer que tous les volumes de swap sont montés avant de lancer le calcul et d'activer systemd-oomd.

[Unit]
Description=Recalculer SwapUsedLimit et redémarrer systemd-oomd au boot
After=multi-user.target

[Service]
Type=oneshot
ExecStartPre=/bin/sleep 120
ExecStartPre=/usr/local/lib/oomd-update-swap-limit.sh
ExecStart=/bin/systemctl restart systemd-oomd.service

[Install]
WantedBy=multi-user.target

Monitoring et Résilience

Le playbook inclut une gestion d'erreurs (rescue) qui envoie un rapport détaillé par mail en cas de défaillance d'une des étapes. Cela permet une intervention rapide si, par exemple, le disque est plein et empêche la création du swapfile.

Annexe

ref : https://www.freedesktop.org/software/systemd/man/latest/systemd-oomd.service.html , https://man.archlinux.org/man/systemd-oomd.8