OOM-KILLER en Linux: Protege mysql

En una configuración típica para un cms o ecommerce en php suelen cohabitar en el mismo servidor varios servicios con grandes necesidades de memoria según la situación. Principalmente estos son php y mysql. Que si php está en apache como módulo o como fpm no viene al caso y será cada administrador quien busque su mejor configuración según requerimientos y necesidades. Luego habrá quien opte por separar servicios en diferentes servidores para mejorar la seguridad y resiliencia a fallos, pero eso es otra historia.

En todo caso, siempre que se configura un sistema se intenta parametrizar de la mejor forma posible los diferentes servicios para que no se produzca un mayor uso de memoria que el disponible en el servidor. Y esto no es tarea fácil. Por un lado hay que intentar pensar en los casos extremos de máxima carga donde todos los servicios estén al máximo de sus configuraciones permitidas y/o necesarias, por otro, hay que tener en cuenta el coste de la memoria, mas aún hoy en día con la moda de los VPS/CLOUD donde retrocedemos a la época de los antiguos dedicados donde la cantidad de RAM disponible era escasa y cara y no es conveniente desperdiciarla. Como bien sabréis es un cálculo difícil y generalmente se juega muy al límite o fuera de él ya que el 99% de las veces nunca se está al 100% de uso de memoria de cada servicio. Esto podría dar para muchas líneas de opiniones, ideas y posibles configuraciones y estrategias, pero voy a centrarme en el objetivo de la entrada: cuando se llega al temido OOM-KILLER.

Este acrónimo viene a significar una protección del kernel que cuando se ve a punto de quedarse sin memoria se saca un algoritmo «simple» de la manga para matar la primera aplicación que piensa que está ocupando mas memoria y que es sacrificable. ¿ Y cual proceso de una configuración típica php+mysql suele ser el mejor candidato ? Si señor, mysql generalmente es el proceso que mayor memoria ocupa en cada momento y el que tiene todas las papeletas de salir premiado. ¿ Y cual es el problema ? que un oom-killer no es nada sutil y cuando te mata, te mata, no espera a que cierres ficheros ni termines ninguna operación intermedia y esto para una base de datos puede ser catastrófico. El problema no será que te llamen (o que deberías detectar antes que el cliente) con que se ha caído la web y vayas y reinicies mysql, la cara de pánico te entrará cuando veas que alguna que otra tabla fundamental está corrupta y de tan mala manera que no es posible repararla fácilmente.

¿ Interesante no ? Pues busquemos una solución.

Evitar que el kernel lance el temido oom-killes es imposible y no podemos evitarlo, lo que si podemos es jugar con el algoritmo para quitarle la idea de que mate mysql. Os dejo una tarea cron de ejemplo que puede salvaros de varios angustiosos momentos:

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

El ejemplo es simple, buscamos el PID del proceso mysql en ejecución cada minuto y le asignamos una prioridad en el atributo oom_score_adj para que el algoritmo le de la menor prioridad posible. Como he dicho esto no desactiva el oom-killer solo lo hacer buscar otro candidato. Generalmente el siguiente en la lista de candidatos suele ser un proceso php o apache (o redis, o ES o…) pero estos, aunque puedan echar abajo una transacción de compra de un cliente, no es tan crítico como corromper la base de datos y dejar el sitio completamente KO durante puede que horas si no andas espabilado y tienes mala suerte.