Mi servidor web VPS que se ejecuta en CentOS 5.4 (kernel de Linux 2.6.16.33-xenU) de forma irregular (como una vez al mes, más o menos unas pocas semanas) deja de responder debido a la aparición de Oom-Killer. El monitoreo del servidor muestra que no normalmente se queda sin memoria, solo de vez en cuando.
He leído un par de blogs que apuntan a esta página que discute la configuración del kernel para gestionar mejor el exceso de compromiso utilizando la siguiente configuración de sysctl:
vm.overcommit_memory = 2
vm.overcommit_ratio = 80
Mi comprensión de esto (que puede estar equivocado, pero no puedo encontrar una definición canónica para aclarar) es que esto evita que el núcleo sobreasigne la memoria más allá del intercambio + 80% de la memoria física.
Sin embargo, también he leído algunas otras fuentes que sugieren que esta configuración no es una buena idea, aunque los críticos de este enfoque parecen estar diciendo "no hagas cosas para romper tu sistema, en lugar de intentar este error" en el supuesto de que La causalidad es siempre conocida.
Entonces, mi pregunta es, ¿cuáles son los pros y los contras de este enfoque , en el contexto de un servidor web Apache2 que aloja alrededor de 10 sitios de bajo tráfico? En mi caso específico, el servidor web tiene 512Mb de RAM, con 1024Mb de espacio de intercambio. Esto parece ser adecuado para la gran mayoría de las veces.
/proc/<PID>/oom_score_adj
para este propósito. Por ejemplo, si configura oom_score_adj en -1000 para sshd, el asesino de oom nunca apuntará a sshd cuando quiera matar algo. Detener por completo a Oom Killer no es una buena idea, ya que tus programas no podrán mallocar la memoria y morirán de todos modos.La Sección 9.6 "Sobrecompromiso y OOM" en el documento que @dunxd menciona es particularmente gráfica sobre los peligros de permitir el sobrecompromiso. Sin embargo, también
80
me pareció interesante, así que realicé algunas pruebas.Lo que encontré es que
overcommit_ratio
afecta la RAM total disponible para TODOS los procesos. Los procesos raíz no parecen ser tratados de manera diferente a los procesos normales del usuario.Establecer la relación en
100
o menos debería proporcionar la semántica clásica donde los valores de retornomalloc/sbrk
son confiables. Establecer relaciones más bajas de100
lo que podría ser una forma de reservar más RAM para actividades que no son de proceso, como el almacenamiento en caché, etc.Entonces, en mi computadora con 24 GiB de RAM, con el intercambio deshabilitado, 9 GiB en uso,
top
mostrandoAquí hay algunas
overcommit_ratio
configuraciones y la cantidad de RAM que mi programa ram-consumer podría tomar (tocar cada página): en cada caso, el programa salió limpiamente una vez quemalloc
falló.Ejecutar varios a la vez, incluso con algunos como usuario root, no cambió la cantidad total que consumieron juntos. Es interesante que no haya podido consumir los últimos 3+ GiB más o menos; el
free
no cayó mucho por debajo de lo que se muestra aquí:Los experimentos fueron desordenados: cualquier cosa que use malloc en el momento en que toda la RAM está en uso tiende a fallar, ya que muchos programadores son terribles al verificar fallas de malloc en C, algunas bibliotecas de colecciones populares lo ignoran por completo, y C ++ y varios otros lenguajes son incluso peor.
La mayoría de las primeras implementaciones de RAM imaginaria que vi fueron para manejar un caso muy específico, donde un solo proceso grande, digamos 51% + de memoria disponible, era necesario
fork()
paraexec()
algún programa de soporte, generalmente mucho, mucho más pequeño. Los sistemas operativos con semántica de copia en escritura permitirían lafork()
, pero con la condición de que si el proceso bifurcado realmente intentara modificar demasiadas páginas de memoria (cada una de las cuales tendría que ser instanciada como una nueva página independiente del gran proceso inicial) terminaría siendo asesinado. El proceso padre solo estaba en peligro si asignaba más memoria, y podía manejar el agotamiento, en algunos casos solo esperando un poco para que otro proceso muriera, y luego continuar. El proceso secundario generalmente solo se reemplazó con un programa (generalmente más pequeño) a través deexec()
y luego estaba libre de la condición.El concepto de exceso de compromiso de Linux es un enfoque extremo para permitir
fork()
que ocurra tanto como para permitir que los procesos individuales se sobreasignen masivamente. Muertes OOM-killer-causado ocurren de forma asíncrona, incluso a los programas que hacen la asignación de memoria mango con responsabilidad. Personalmente, odio el exceso de compromiso en todo el sistema en general y el asesino de Oom en particular: fomenta un enfoque de cuidado del diablo para la gestión de la memoria que infecta las bibliotecas y, a través de ellas, todas las aplicaciones que las usan.Sugeriría establecer la proporción en 100, y tener una partición de intercambio que generalmente solo terminaría siendo utilizada por procesos enormes, que a menudo solo usan una pequeña fracción de la parte de sí mismos que se rellena en el intercambio, y por lo tanto proteja la gran mayoría de los procesos de la mala característica del OOM asesino. Esto debería mantener su servidor web a salvo de una muerte aleatoria, y si fue escrito para manejar de manera
malloc
responsable, incluso a salvo de suicidarse (pero no apueste por el último).Eso significa que estoy usando esto en
/etc/sysctl.d/10-no-overcommit.conf
fuente