Cómo configurar en Linux el cancelador de procesos por memoria insuficiente OOM

Por Robert Chase
Publicado en Noviembre 2015

Acerca del cancelador OOM
Cuando un servidor que aloja una base de datos o aplicación deja de funcionar, suele ser necesario trabajar vertiginosamente para restablecer los servicios críticos, en especial si se trata de sistemas de producción importantes. Al intentar determinar la causa del problema, una vez superada la desesperación inicial, a menudo no se comprende por qué la aplicación o base de datos dejó de funcionar repentinamente. En ciertas situaciones, la interrupción se debe a que el sistema advierte que no tiene memoria suficiente y cancela un proceso importante para poder seguir funcionando.

El kernel de Linux asigna memoria en función de la demanda de las aplicaciones que se ejecutan en el sistema. Como en el caso de muchas aplicaciones la memoria se asigna desde que comienzan a ejecutarse, pero luego no se la utiliza, el kernel fue diseñado para sobreasignar memoria de modo de eficientizar su uso. El modelo de sobreasignación permite que el kernel asigne más memoria de la disponible en los componentes físicos. Si un proceso utiliza toda  la memoria que le fue asignada, el kernel le proporciona a la aplicación los recursos adicionales. Cuando son demasiadas las aplicaciones que utilizan toda la memoria que les fue asignada, el modelo de sobreasignación puede volverse problemático, y el kernel debe cancelar procesos para seguir operativo. El mecanismo que emplea el kernel para recuperar memoria del sistema se conoce como cancelador de procesos por memoria insuficiente (out-of-memory killer) o, abreviado, cancelador OOM (OOM killer).

Cómo averiguar por qué se canceló un proceso
Cuando se busca solucionar un problema en el que el cancelador OOM canceló una aplicación, es posible seguir diversos indicios que podrían arrojar luz sobre el cómo y el porqué de la cancelación del proceso. En el ejemplo que sigue, vamos a echar un vistazo al registro syslog para ver si podemos hallar el origen del problema. El proceso oracle fue cancelado por el cancelador OOM porque se presentó un estado de memoria insuficiente en el sistema. La K mayúscula de Killed [canceló] señala que el proceso fue cancelado con una señal -9, lo que indica con bastante certeza que el cancelador OOM podría ser el culpable.

grep -i kill /var/log/messages*  
host kernel: Out of Memory: Killed process 2592 (oracle).


También es posible examinar el estado de utilización de la memoria baja y alta del sistema. Cabe señalar que como esos valores se informan en tiempo real y cambian en función de la carga de trabajo del sistema, debería observárselos frecuentemente para detectar cuando la memoria se vea sobreexigida. Observarlos tras la cancelación de un proceso no aportará demasiada información ni contribuirá al esclarecimiento de problemas relacionados con el cancelador OOM.

[root@test-sys1 ~]# free -lm               
                   total       used       free     shared    buffers     cached  
Mem:                 498         93        405          0         15         32  
Low:                 498         93        405  
High:                  0          0          0  
-/+ buffers/cache:               44        453  
Swap:               1023          0       1023

 

En esta máquina virtual de prueba, hay 498 MB de memoria baja libres. El sistema no ha usado el espacio de intercambio. El ///conmutador -l muestra valores estadísticos de las memorias alta y baja  y el ///conmutador -m expresa la salida en megabytes para facilitar la lectura.

[root@test-sys1 ~]# egrep 'High|Low' /proc/meminfo  
HighTotal:             0 kB  
HighFree:              0 kB  
LowTotal:         510444 kB  
LowFree:          414768 kB


Es posible acceder a los mismos datos analizando /proc/memory y mirando especialmente los valores altos y bajos. No obstante, con este último método no se obtiene información sobre la salida con relación el espacio de intercambio, y la salida se ve expresada en kilobytes.

La memoria baja es aquella a la que el kernel tiene acceso físico directo. La memoria alta es aquella para la cual el kernel no tiene una dirección física directa, por lo que la asociación o mapeo se lleva a cabo mediante una dirección virtual. En los sistemas de 32-bits antiguos, se ven la memoria baja y la memoria alta debido al modo en que se asocia la memoria a una dirección virtual. En las plataformas de 64 bits, ya no se necesita espacio con dirección virtual, por lo que toda la memoria del sistema se muestra como memoria baja.

Si bien analizar /proc/memory y emplear el comando free es útil para saber en un momento dado en qué medida se está utilizando la memoria, en ocasiones se necesita conocer la utilización de la memoria a lo largo de un período de tiempo. El comando vmstat es bastante útil en ese sentido.

En el ejemplo, en la Secuencia 1, se emplea el comando vmstat para observar los recursos cada 45 segundos 10 veces. El ///conmutador-s muestra los valores en una tabla y el ///conmutador -M expresa la salida en megabytes para facilitar la lectura. Como puede verse en el ejemplo, hay algo que está consumiendo la memoria libre, pero todavía no se usa el espacio de intercambio.

[root@localhost ~]# vmstat -SM 45 10  
procs -----------memory-------- ---swap-- -----io-- --system-- ----cpu---------   
r  b   swpd  free  buff  cache  si   so   bi   bo   in    cs us  sy  id  wa st   
1  0      0   221   125     42   0    0    0    0   70     4  0   0  100  0  0   
2  0      0   192   133     43   0    0  192   78  432  1809  1  15   81   2 0   
2  1      0    85   161     43   0    0  624  418 1456  8407  7  73    0  21 0   
0  0      0    65   168     43   0    0  158  237  648  5655  3  28   65   4 0   
3  0      0    64   168     43   0    0    0    2 1115 13178  9  69   22   0 0   
7  0      0    60   168     43   0    0    0    5 1319 15509 13  87    0   0 0   
4  0      0    60   168     43   0    0    0    1 1387 15613 14  86    0   0 0   
7  0      0    61   168     43   0    0    0    0 1375 15574 14  86    0   0 0   
2  0      0    64   168     43   0    0    0    0 1355 15722 13  87    0   0 0   
0  0      0    71   168     43   0    0    0    6  215  1895  1   8   91   0 0

Secuencia 1

Es posible redirigir a un archivo la salida de vmstat con el siguiente comando. Incluso se puede ajustar la duración y la cantidad de veces para monitorear los recursos por más tiempo. En cualquier momento durante la ejecución del comando, es posible consultar el archivo de salida para ver los resultados.

En el ejemplo que sigue, la memoria se observa cada 120 segundos 1000 veces. El carácter & al final de la línea permite ejecutar el comando como proceso y recuperar la terminal.

vmstat  -SM 120 1000 > memoryusage.out &


A modo de referencia, en la Secuencia 2 se muestra una sección de la página del manual sobre vmstat que brinda información adicional acerca de la salida que brinda el comando. Se trata solamente de la información referida a la memoria; el comando también provee información sobre las entradas y salidas del disco y sobre la utilización de la CPU.

Memory         
  swpd: the amount of virtual memory used.         
  free: the amount of idle memory.         
  buff: the amount of memory used as buffers.         
  cache: the amount of memory used as cache.         
  inact: the amount of inactive memory. (-a option)         
  active: the amount of active memory. (-a option)       

Swap         
  si: Amount of memory swapped in from disk (/s).         
  so: Amount of memory swapped to disk (/s).

Secuencia 2

Existen otras herramientas para monitorear la memoria y el rendimiento del sistema a fin de indagar acerca de problemas de la naturaleza descripta. Herramientas tales como sar, System Activity Reporter (informador de actividad del sistema), y dtrace, Dynamic Tracing (seguimiento dinámico), son muy útiles para recopilar datos puntuales sobre el rendimiento del sistema a lo largo del tiempo. En caso de querer tener una visibilidad aún mayor, las sondas de estabilidad dtrace y de estabilidad de datos incluso cuentan con un desencadenador de estados OOM que se activa si el kernel cancela un proceso debido a un estado OOM. En la sección "Información adicional" de este artículo se incluyen otros datos sobre los comandos dtrace y sar.

Existen diversas situaciones que pueden dar lugar a un evento OOM, además del agotamiento de la memoria RAM y del espacio de intercambio disponible debido a la carga de trabajo del sistema.  Podría suceder que el kernel no use el espacio de intercambio de manera óptima debido al tipo de carga de trabajo del sistema. En las aplicaciones que emplean llamadas mlock() o páginas HugePages no es posible recurrir al disco cuando la memoria física comienza a agotarse. Puede ocurrir que las estructuras de datos del kernel también empleen demasiado espacio y consuman la memoria del sistema hasta causar un estado OOM.  Numerosos sistemas basados en la arquitectura NUMA pueden presentar situaciones OOM debido a la memoria insuficiente en un nodo y la subsiguiente activación de un proceso OOM en el kernel, cuando en realidad hay mucha memoria disponible en los otros nodos. En la sección "Información adicional" de este artículo se incluyen otros datos sobre los estados OOM de máquinas con arquitectura NUMA.

Configuración del cancelador OOM
El cancelador OOM de Linux ofrece numerosas opciones de configuración que brindan a los desarrolladores alternativas respecto de cómo debe comportarse el sistema ante un estado OOM.  Los parámetros y valores que se seleccionen dependerán del entorno y de las aplicaciones que tenga configuradas el sistema en ese entorno.

Nota: Se sugiere llevar a cabo las pruebas y ajustes necesarios en un entorno de desarrollo antes de introducir cambios que modifiquen sistemas de producción importantes.

En algunos entornos, cuando se ejecuta una única tarea crítica, reiniciar el sistema si se registra un estado OOM podría ser una alternativa viable para restablecer el funcionamiento normal rápidamente y sin intervención del administrador.  Si bien el anterior no es un enfoque óptimo, responde a la lógica de que si la aplicación deja de funcionar porque la interrumpe el cancelador OOM, el reinicio del sistema restablecerá la aplicación si esta comienza a ejecutarse junto con el sistema durante el reinicio. Si es el administrador quien debe ejecutar la aplicación manualmente, la opción mencionada no dará los resultados deseados.

Los valores que se indican a continuación causarán una situación de "pánico" en el sistema y el consiguiente reinicio ante el estado de memoria insuficiente. Los comandos sysctl asignarán los valores en tiempo real y, si se agregan esas asignaciones a sysctl.conf, la configuración no se perderá tras nuevos reinicios. El valor X para kernel.panic indica los segundos que deberán pasar antes del reinicio del sistema. Ese valor debe ajustarse en función de las necesidades del entorno concreto.

sysctl vm.panic_on_oom=1  
sysctl kernel.panic=X  
echo "vm.panic_on_oom=1" >> /etc/sysctl.conf  
echo "kernel.panic=X" >> /etc/sysctl.conf


Además, aplicando ciertos procesos es posible ajustar la forma en que el cancelador OOM reacciona ante estados OOM.  Consideremos, por ejemplo, el proceso oracle 2592 cancelado anteriormente. Si queremos reducir las probabilidades de que el proceso oracle sea interrumpido por el cancelador OOM, podemos usar la instrucción que se indica a continuación:

echo -15 > /proc/2592/oom_adj


Si, en cambio, queremos aumentar las probabilidades de que el cancelador OOM interrumpa el proceso oracle, podemos hacer lo siguiente:

echo 10 > /proc/2592/oom_adj


Si queremos excluir por completo el proceso oracle del alcance del cancelador OOM, podemos usar la instrucción que se indica abajo. Es importante señalar que la instrucción indicada puede provocar un comportamiento inesperado en función de los recursos y la configuración del sistema. Si el kernel no logra cancelar un proceso que emplea una importante cantidad de memoria, se ocupará de otros procesos disponibles. Puede suceder que algunos de esos procesos sean esenciales para el sistema operativo y que su cancelación provoque que todo el sistema deje de funcionar.

echo -17 > /proc/2592/oom_adj


Es posible asignar valores válidos entre -16 y +15 a oom_adj; si se le asigna el valor -17, se excluirá por completo el proceso del alcance del cancelador OOM. Cuanto más alto sea el valor, mayores serán las probabilidades de que el cancelador elija interrumpir el proceso en cuestión ante un estado OOM del sistema. También es posible ver el contenido de /proc/2592/oom_score para determinar el grado de probabilidad de que el cancelador OOM interrumpa un proceso. El valor 0 indica que el proceso está excluido del alcance del cancelador OOM. Cuanto más alto sea el valor de oom_score, mayores serán las probabilidades de que se interrumpa el proceso ante un estado OOM del sistema.

Es posible desactivar el cancelador OOM por completo mediante el código que aparece más abajo. No se recomienda su utilización en entornos de producción, porque si efectivamente se presentara un estado OOM, podrían registrarse comportamientos inesperados en función de los recursos disponibles y las configuraciones del sistema. Los comportamientos inesperados pueden incluir desde una situación de pánico del kernel hasta el congelamiento del sistema según qué recursos tenga disponible el kernel cuando se presente el estado OOM.

sysctl vm.overcommit_memory=2  
echo "vm.overcommit_memory=2" >> /etc/sysctl.conf


En el caso de algunos entornos, las opciones de configuración mencionadas no son óptimas y pueden ser necesarios nuevos ajustes. La configuración de páginas HugePages para el kernel puede ayudar a hacer frente a eventos OOM en función de las necesidades de las aplicaciones que se ejecuten en el sistema.

Información adicional
A continuación se mencionan recursos adicionales que se refieren a HugePages, dtrace, sar y OOM para arquitecturas NUMA:

 


Robert Chase es miembro del equipo de gestión de productos Oracle Linux. Ha trabajado con Linux y software de código abierto desde 1996. Asimismo, ha trabajado con sistemas tan pequeños como dispositivos incrustados y con grandes superequipos.

Este artículo ha sido revisado por el equipo de productos Oracle y se encuentra en cumplimiento de las normas y prácticas para el uso de los productos Oracle.