Efectos de configurar vm.overcommit_memory

41

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.

dunxd
fuente

Respuestas:

32

Establecer overcommit_ratioen 80 probablemente no sea la acción correcta. Establecer el valor a menos de 100 es casi siempre incorrecto.

La razón de esto es que las aplicaciones de Linux asignan más de lo que realmente necesitan. Digamos que asignan 8kb para almacenar una cadena de texto de un par de caracteres. Bueno, eso es varios KB no utilizados allí. Las aplicaciones hacen mucho esto, y para eso está diseñado el exceso de compromiso.

Básicamente, con un exceso de compromiso de 100, el kernel no permitirá que las aplicaciones asignen más memoria de la que tiene (swap + ram). Establecerlo en menos de 100 significa que nunca usará toda su memoria. Si va a establecer esta configuración, debe establecerla por encima de 100 debido al escenario mencionado anteriormente, que es bastante común.

Ahora, en cuanto a su problema con la activación del asesino OOM, la configuración manual de sobrecompromiso probablemente no solucionará esto. La configuración predeterminada (determinación heurística) es bastante inteligente.

Si desea ver si esta es realmente la causa del problema, observe /proc/meminfocuándo se ejecuta el asesino OOM. Si ve que Committed_ASestá cerca CommitLimit, pero freeaún muestra memoria libre disponible, entonces sí, puede ajustar manualmente el exceso de compromiso para su escenario. Establecer este valor demasiado bajo causará que el asesino de OOM comience a matar aplicaciones cuando todavía tenga mucha memoria libre. Establecerlo demasiado alto puede causar que las aplicaciones aleatorias mueran cuando intentan usar la memoria que se les asignó, pero en realidad no está disponible (cuando toda la memoria se agota).

Patricio
fuente
1
Gracias. Estoy intentando cosas con overcommit_ratio establecido en 100 para ver qué sucede. El principal problema que tengo es que cuando se inicia oom-killer, invariablemente mata sshd evitando que acceda al servidor y vea lo que está sucediendo. Supongo que lo que realmente necesito es evitar que Oom-Killer se ejecute y algunos medios para registrar lo que sucede cuando se hubiera ejecutado para poder encontrar la causa del problema.
dunxd
44
@dunxd puedes usar /proc/<PID>/oom_score_adjpara 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.
Patrick
44
@dunxd es heredado. haga que su script de inicio lo establezca en sí mismo, y cualquier cosa iniciada por el script de inicio lo hereda.
Patrick
44
Su ejemplo de 4 KB es incorrecto. La memoria virtual se usa con páginas y el tamaño (más pequeño) de una página en Linux es de 4 KB. Eso significa que almacenar un par de caracteres requiere que se asignen 4 KB en algún lugar, independientemente de la configuración de sobrecompromiso. Un ejemplo adecuado de memoria sobre compromiso sería, por ejemplo, asignar 10 KB y solo usar los primeros 4100 bytes. Eso significa que dos páginas de 4 KB necesitan almacenar los datos y una página adicional no se usa. Los sistemas que no se comprometen demasiado siempre tendrán esa tercera página lista para almacenar datos en caso de que llegue la demanda, los sistemas que se comprometen no lo harán cumplir.
jlliagre
2
/ proc / self apunta al proceso actual, por lo que / proc / self / oom_score_adj podría usarse para cambiar oom_score_adj del proceso actual.
r_2
23

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 80me pareció interesante, así que realicé algunas pruebas.

Lo que encontré es que overcommit_ratioafecta 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 100o menos debería proporcionar la semántica clásica donde los valores de retorno malloc/sbrkson confiables. Establecer relaciones más bajas de 100lo 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, topmostrando

Mem:  24683652k total,  9207532k used, 15476120k free,    19668k buffers
Swap:        0k total,        0k used,        0k free,   241804k cached

Aquí hay algunas overcommit_ratioconfiguraciones 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 que mallocfalló.

 50    ~680 MiB
 60   ~2900 MiB
 70   ~5200 MiB
100  ~12000 MiB

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 freeno cayó mucho por debajo de lo que se muestra aquí:

Mem:  24683652k total, 20968212k used,  3715440k free,    20828k buffers

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()para exec()algún programa de soporte, generalmente mucho, mucho más pequeño. Los sistemas operativos con semántica de copia en escritura permitirían la fork(), 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 mallocresponsable, 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

vm.overcommit_memory = 2
vm.overcommit_ratio = 100
Alex North-Keys
fuente
¿Y recomendaría mantener vm.overcommit_memory a 2?
Ut xD
1
Buena nota: eso es lo que estoy usando; Creo que lo omití en mi respuesta porque ya está en la pregunta
Alex North-Keys