J’ai été récemment confronté à une erreur type « ouf-of-memory » sur un serveur linux hébergeant un PostgreSQL. Aucune alerte mémoire dans la supervision. Je me connecte sur la machine et fait un free -m qui ne relève aucune anomalie :

En gros 9Go de la RAM est utilisée pour le cache et 190Mo est libre. WTF?!

Je vérifie coté ulimit :

Aucune limitation sur le process.

Petite subtilité, ce serveur héberge une base postgreSQL et il est configuré pour refuser la sur-allocation de mémoire. Hé oui, linux effectue une sur-allocation de mémoire. Il faut se dire qu’il y a pleins de process qui demandent une certaine quantité de mémoire allouée mais qui au final en consomme très peu. Sur l’ensemble des process d’une machine ça fonctionne sans trop poser de problème. Sauf quand les process se mettent à consommer la mémoire qui leur a été allouée.

L’utilisation mémoire va monter petit à petit, la machine va utiliser la swap puis en dernier recours l’OOM Killer (Out-Of-Memory Killer) 1 va rentrer en jeu. Celui-ci va killer des processus de manière heuristique afin de libérer la mémoire. Sur un serveur et à fortiori un serveur de base de données on veut éviter à tout prix ce comportement. Donc on désactive l’overcommit.

Ça se fait en passant le paramètre vm.overcommit_memory à 2 dans le fichier /etc/sysctl.conf (ça peut aussi se faire à chaud). 2

Ce paramètre va de pair avec vm.overcommit_ratio. Celui-ci indique au noyau la quantité de mémoire qui peut être allouée.  En gros RAM * ratio /100 + SWAP. 3

On peut aussi en profiter pour configurer le paramètre vm.swappiness. Celui-ci défini l’utilisation de la swap, une valeur élevée et le système va privilégier la swap, une valeur faible et le système va privilégier la RAM.

Revenons à notre patient, voici ses constantes :

Ça n’explique toujours pas pourquoi le système refuse d’allouer plus de mémoire. A force gratter avec mon collègue, on a fini par trouver. En regardant dans /proc/meminfo il faut surveiller ces deux valeurs :

CommitLimit et Committed_AS. 4 CommitLimit donne la quantité maximale de mémoire qui peut être allouée (RAM + SWAP). Committed_AS indique la mémoire actuellement allouée, qui n’a rien à voir avec les valeurs retournées par free -m. Dans notre cas les deux valeurs étaient très proches. Dans l’urgence on avait augmenté la mémoire (les vm c’est pratiques!) mais je pense que la différence entre les deux valeurs était tellement faible que la machine ne pouvait plus allouer de mémoire.

On tient enfin notre explication! Pour solutionner le problème on peut tout simplement augmenter la mémoire RAM ou le SWAP. C’est là que commence de grand débats, faut-il ou non de la swap sur un serveur sachant qu’on en veut pas que la swap soit utilisée.

Il y a différentes approches possible, ça dépend de plusieurs paramètres : Disponibilité et cout de la RAM, utilisation de la mémoire allouée par les process …

Comme on le sait une machine linux va utiliser la totalité de sa RAM. La mémoire qui n’est pas utilisée pour les process sert de cache disque. Quel intérêt à avoir 9Go de cache en lecture pour les buffer et le cache? Assez peu à mon gout, certes il en faut mais c’est peut être du gâchis d’en avoir autant.

On peut augmenter la swap afin d’influer sur le paramètre CommitLimit. Cette décision se fait aussi en fonction de l’utilisation la RAM réelle (free -m). Dans notre cas la mémoire était utilisée à tout juste 50% pour les process.  Ainsi en augmentant la swap on va augmenter la valeur de CommitLimit en considérant que les process n’utilisent pas la totalité de la mémoire qui leur a été allouée.

Bien entendu il faut surveiller toutes ces valeurs. Si les process se mettaient à utiliser toute la mémoire qui leur a été allouée le système serait obligé d’utiliser la swap.

J’ai d’ailleurs été surpris de ne trouver aucune sonde nagios permettant de monitorer les valeurs d’allocations de la mémoire par snmp. Visiblement le démon snmp ne remonte pas ces infos. Ça ne doit pas être bien dur à mettre en place, il faut choisir un numéro de mib et associer un script qu’exécutera le démon pour récupérer les valeurs.

Share

One thought on “Swap et overcommit sous linux

  1. Et comme vu récemment chez un client : si tu as plusieurs instances PostgreSQL sur le même serveur, les shared_buffers s’additionnent pour calculer le CommitLimit_AS, *même s’ils ne sont pas utilisés !*

    5 instances à 4 Go de SB
    -> 20 Go dans CommitLimit_AS d’entrée.

    En conséquence avec 20 Go de RAM libres (car les SB n’étaient pas utilisés), des psql ou des autovacuum se voyaient refuser la moindre mémoire par le système.

    Pas de solution simple sinon regrouper des instances ou réduire au max les shared_buffers.

    Répondre

Ecrire un commentaire

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url=""> 

requis