OOM-KILLER sous Linux : Protéger MySQL

Dans une configuration typique pour un CMS ou un e-commerce PHP, plusieurs services aux besoins importants en mémoire cohabitent généralement sur le même serveur selon la situation. Principalement ce sont PHP et MySQL. Que PHP soit dans Apache comme module ou comme FPM n’est pas le sujet et c’est à chaque administrateur de trouver sa meilleure configuration selon les exigences et les besoins. Ensuite il y a ceux qui optent pour séparer les services sur différents serveurs pour améliorer la sécurité et la résilience aux pannes, mais c’est une autre histoire.

Dans tous les cas, chaque fois qu’un système est configuré, on essaie de paramétrer au mieux les différents services pour qu’il n’y ait pas d’utilisation de mémoire supérieure à celle disponible sur le serveur. Et ce n’est pas une tâche facile. D’un côté il faut essayer de penser aux cas extrêmes de charge maximale où tous les services sont au maximum de leurs configurations permises et/ou nécessaires, de l’autre, il faut prendre en compte le coût de la mémoire, d’autant plus aujourd’hui avec la mode des VPS/Cloud où on revient à l’époque des anciens dédiés où la quantité de RAM disponible était limitée et chère et il n’est pas pratique de la gaspiller. Comme vous le savez bien c’est un calcul difficile et généralement on joue très à la limite ou au-delà car 99% du temps on n’est jamais à 100% d’utilisation de mémoire de chaque service. Cela pourrait donner lieu à de nombreuses lignes d’opinions, d’idées et de possibles configurations et stratégies, mais je vais me concentrer sur l’objectif de cet article : quand on arrive au redouté OOM-KILLER.

Cet acronyme désigne une protection du noyau qui, quand il se trouve sur le point de manquer de mémoire, sort un algorithme « simple » de sa manche pour tuer la première application qui selon lui occupe le plus de mémoire et qui est sacrifiable. Et quel processus dans une configuration typique PHP+MySQL est généralement le meilleur candidat ? Oui, MySQL est généralement le processus qui occupe le plus de mémoire à chaque instant et celui qui a toutes les chances de sortir gagnant. Et quel est le problème ? qu’un OOM-killer n’est pas du tout subtil et quand il vous tue, il vous tue, il n’attend pas que vous fermiez des fichiers ni que vous terminiez une opération intermédiaire et cela pour une base de données peut être catastrophique. Le problème ne sera pas qu’on vous appelle (ou que vous devriez détecter avant le client) que le site web est tombé et que vous allez redémarrer MySQL, la panique vous gagnera quand vous verrez qu’une table fondamentale est corrompue et de si mauvaise façon qu’il n’est pas possible de la réparer facilement.

Intéressant non ? Cherchons donc une solution.

Empêcher le noyau de lancer le redouté OOM-killer est impossible et nous ne pouvons pas l’éviter, ce que nous pouvons faire c’est jouer avec l’algorithme pour lui ôter l’idée de tuer MySQL. Voici un exemple de tâche cron qui peut vous sauver de plusieurs moments angoissants :

* * * * * pgrep -f mysqld| while read PID; do echo -1000 > /proc/$PID/oom_score_adj; done

L’exemple est simple, nous cherchons le PID du processus MySQL en cours d’exécution chaque minute et nous lui assignons une priorité dans l’attribut oom_score_adj pour que l’algorithme lui donne la priorité la plus basse possible. Comme je l’ai dit cela ne désactive pas l’OOM-killer seulement lui fait chercher un autre candidat. Généralement le suivant sur la liste des candidats est habituellement un processus PHP ou Apache (ou Redis, ou ES ou…) mais ceux-ci, bien qu’ils puissent faire tomber une transaction d’achat client, ne sont pas aussi critiques que de corrompre la base de données et laisser le site complètement KO pendant peut-être des heures si vous n’êtes pas rapide et avez de la malchance.

Laisser un commentaire

Este formulario guarda los datos que indiques de nombre, email y comentario para poder realizar un seguimiento de los comentarios dejados en cada entrada.