¿Desactiva el asesino OOM de Linux de forma predeterminada?

37

El asesino de OOM en Linux causa estragos en varias aplicaciones de vez en cuando, y parece que realmente no se hace mucho en el lado del desarrollo del kernel para mejorar esto. ¿No sería mejor, como práctica recomendada al configurar un nuevo servidor , revertir el valor predeterminado en la sobrecompromiso de memoria, es decir, desactivarlo ( vm.overcommit_memory=2) a menos que sepa que lo desea para su uso particular? ¿Y cuáles serían esos casos de uso en los que sabes que quieres comprometerte demasiado?

Como beneficio adicional, dado que el comportamiento en caso de vm.overcommit_memory=2depende del vm.overcommit_ratioespacio e intercambio, ¿cuál sería una buena regla general para dimensionar los dos últimos para que toda esta configuración siga funcionando razonablemente?

Peter Eisentraut
fuente

Respuestas:

63

Una analogía interesante (de http://lwn.net/Articles/104179/ ):

Una compañía de aviones descubrió que era más barato volar sus aviones con menos combustible a bordo. Los aviones serían más ligeros y usarían menos combustible y se ahorraría dinero. Sin embargo, en raras ocasiones la cantidad de combustible era insuficiente y el avión se estrellaría. Los ingenieros de la compañía resolvieron este problema mediante el desarrollo de un mecanismo especial OOF (sin combustible). En casos de emergencia, un pasajero fue seleccionado y expulsado del avión. (Cuando fue necesario, el procedimiento se repitió). Se desarrolló una gran cantidad de teoría y se dedicaron muchas publicaciones al problema de seleccionar adecuadamente a la víctima para ser expulsada. ¿Se debe elegir a la víctima al azar? ¿O debería uno elegir a la persona más pesada? O el mayor? Si los pasajeros pagan para no ser expulsados, para que la víctima sea la más pobre a bordo? Y si, por ejemplo, se eligió a la persona más pesada, ¿debería haber una excepción especial en caso de que fuera el piloto? ¿Deberían estar exentos los pasajeros de primera clase? Ahora que existía el mecanismo OOF, se activaría de vez en cuando y expulsaría a los pasajeros incluso cuando no hubiera escasez de combustible. Los ingenieros todavía están estudiando con precisión cómo se causa este mal funcionamiento.

Andrés
fuente
11
Lo disfruté mucho, gracias por desenterrarlo.
Nick Bolton
32

El asesino OOM solo causa estragos si ha sobrecargado su sistema. Intercambie lo suficiente y no ejecute aplicaciones que de repente decidan comer grandes cantidades de RAM, y no tendrá ningún problema.

Para responder específicamente a sus preguntas:

  • No creo que sea una buena idea desactivar el exceso de compromiso en el caso general; Se escriben muy pocas aplicaciones para tratar adecuadamente brk(2) (y los contenedores que lo usan, como malloc(3)) devuelven un error. Cuando experimenté con esto en mi trabajo anterior, se consideró que era más complicado conseguir todo lo que fuera capaz de manejar errores de falta de memoria que solo lidiar con las consecuencias de un OOM (que, en nuestro caso, fue mucho peor que tener que reiniciar el servicio ocasional si ocurría una OOM: tuvimos que reiniciar un clúster completo, porque GFS es una pila de heces humeantes).
  • Desea comprometerse en exceso para cualquier proceso que comprometa en exceso la memoria. Los dos culpables más comunes aquí son Apache y la JVM, pero muchas aplicaciones lo hacen en mayor o menor grado. Ellos piensan que podrían necesitar una gran cantidad de memoria en algún momento en el futuro, por lo que tomar un gran trozo de la derecha. En un sistema con exceso de compromiso, el kernel dice "meh, lo que sea, ven a molestarme cuando realmente quieras escribir en esas páginas" y no pasa nada malo. En un sistema de sobrecompromiso, el kernel dice "no, no puedes tener tanta memoria, si por casualidad escribes todo en algún momento en el futuro estoy deshuesado, ¡así que no hay memoria para ti!" y la asignación falla. Como nadasale "oh, OK, ¿puedo tener esta menor cantidad de segmento de datos de proceso?", entonces el proceso (a) se cierra con un error de falta de memoria o (b) no verifica el código de retorno de malloc, piensa que está bien ir, y escribe en una ubicación de memoria no válida, lo que provoca una falla de seguridad. Afortunadamente, la JVM hace todo su preasignación al inicio (por lo que su JVM se inicia o muere inmediatamente, lo que generalmente nota), pero Apache hace cosas funky con cada nuevo niño, lo que puede tener efectos emocionantes en la producción (irreproducible "no manejando conexiones "tipos de emoción).
  • No me gustaría establecer mi overcommit_ratio más alto que el valor predeterminado del 50%. Una vez más, según mis pruebas, aunque configurarlo alrededor de 80 o 90 puede parecer una buena idea, el núcleo requiere grandes cantidades de memoria en momentos inconvenientes, y un sistema completamente cargado con una alta relación de sobrecompromiso probablemente no tenga suficiente memoria de reserva cuando el núcleo lo necesita (lo que genera miedo, pestilencia y ups). Por lo tanto, jugar con exceso de compromiso presenta un nuevo modo de falla aún más divertido, en lugar de simplemente reiniciar cualquier proceso que se OOM cuando se quede sin memoria, ahora su máquina se bloquea, lo que provoca una interrupción de todo en la máquina. ¡INCREÍBLE!
  • El espacio de intercambio en un sistema libre de exceso de compromiso depende de la cantidad de memoria solicitada pero no utilizada que necesitan sus aplicaciones, más un margen de seguridad saludable. Resolver lo que se necesita en un caso específico se deja como ejercicio para el lector.

Básicamente, mi experiencia es que desactivar el exceso de compromiso es un buen experimento que rara vez funciona tan bien en la práctica como suena en teoría. Esto se corresponde muy bien con mis experiencias con otros ajustables en el kernel: los desarrolladores del kernel de Linux son casi siempre más inteligentes que usted, y los valores predeterminados funcionan mejor para la gran mayoría de los casos. Déjelos en paz y, en su lugar, busque qué proceso tiene la fuga y arréglelo.

womble
fuente
2
No quiero que se elimine mi proceso de copia de seguridad porque alguien está haciendo DoS en mi servidor web. Las excepciones están bien, pero el valor predeterminado debe ser la seguridad y la coherencia. Las optimizaciones como OOM deben activarse manualmente en mi humilde opinión. Es como codificar, se codifica limpiamente y luego se optimiza. Over-commit es una buena característica, pero no debería ser la predeterminada.
Aki
1
Si no desea que su proceso de copia de seguridad se cierre porque alguien está haciendo DoS en su servidor web, no configure su servidor web de tal manera que un DoS pueda hacer que los recursos en el sistema se abrumen.
womble
Tengo 8 GB de RAM y solo ejecuto Firefox y una máquina virtual a veces resulta en el asesino OOM que mata la VM. Compilando Unreal Engine 4, cada invocación de clanes toma 1 ~ 1.5GB de memoria y nuevamente, el asesino OOM mata a uno de vez en cuando. Ahora, en general, estoy de acuerdo con eso, sin el asesino de OOM probablemente de todos modos se desconectarían. Es solo que cada vez que el asesino de OOM quiere matar un proceso, mi sistema se congela durante 10 minutos antes de que el proceso malo se mate realmente. Error tal vez? Más probable. Lo quiero Definitivamente no. Y esa es su razón por la que uno podría deshabilitar el asesino OOM.
Shahbaz
1
Si está haciendo todo eso en una caja, necesita más RAM, y deshabilitar el exceso de compromiso solo lo empeorará.
Ben Lutgens
6

Hmm, no estoy completamente convencido por los argumentos a favor del exceso de compromiso y el asesino OOM ... Cuando womble escribe,

"El asesino OOM solo causa estragos si has sobrecargado tu sistema. Dale suficiente intercambio y no ejecutes aplicaciones que de repente decidan comer grandes cantidades de RAM, y no tendrás ningún problema".

Se trata de describir un escenario de entorno en el que el sobrecompromiso y el asesino de OOM no se aplican, o no 'realmente' actúan (si todas las aplicaciones asignan memoria según sea necesario, y hubiera suficiente memoria virtual para asignar, las escrituras en memoria seguirían de cerca las asignaciones de memoria sin errores, por lo que realmente no podríamos hablar sobre un sistema sobrecomprometido, incluso si se habilitara una estrategia de sobrecompromiso). Se trata de una admisión implícita de que el exceso de compromiso y el asesino de OOM funcionan mejor cuando no se necesita su intervención, que de alguna manera es compartida por la mayoría de los partidarios de esta estrategia, hasta donde puedo decir (y admito que no puedo decir mucho ...). Además, al referirme a aplicaciones con comportamientos específicos al preasignar memoria me hace pensar que un manejo específico podría ajustarse a un nivel de distribución, en lugar de tener un valor predeterminado,

En lo que concierne a la JVM, bueno, es una máquina virtual, en cierta medida necesita asignar todos los recursos que necesita en el inicio, para que pueda crear su entorno 'falso' para sus aplicaciones y mantener sus recursos disponibles separados del host. entorno, en la medida de lo posible. Por lo tanto, puede ser preferible que falle en el inicio, en lugar de después de un tiempo como consecuencia de una condición OOM 'externa' (causada por un exceso de compromiso / asesino OOM / lo que sea), o de todos modos sufriendo por una condición que interfiere con la suya estrategias de manejo interno de OOM (en general, una VM debe obtener los recursos necesarios desde el principio y el sistema host debe 'ignorarlos' hasta el final, de la misma manera que cualquier cantidad de ram física compartida con una tarjeta gráfica nunca es, y no puede ser - Tocado por el sistema operativo).

Sobre Apache, dudo que hacer que todo el servidor se apague y reinicie ocasionalmente es mejor que dejar que un solo niño, junto con una sola conexión, falle desde su inicio (= el niño / la conexión) (como si fuera una instancia completamente nueva de la JVM creada después de otra instancia se ejecuta por un tiempo). Supongo que la mejor 'solución' podría depender de un contexto específico. Por ejemplo, teniendo en cuenta un servicio de comercio electrónico, puede ser preferible tener algunas conexiones con el gráfico de compras que fallan al azar en lugar de perder todo el servicio, con el riesgo, por ejemplo, de interrumpir la finalización de un pedido en curso, o (tal vez peor) un proceso de pago, con todas las consecuencias del caso (tal vez inofensivo, pero tal vez dañino, y seguro, cuando surgieron problemas,

Del mismo modo, en una estación de trabajo, el proceso que consume la mayor cantidad de recursos y, por lo tanto, como la primera opción para el asesino de OOM, podría ser una aplicación de uso intensivo de memoria, como un transcodificador de video o un software de representación, probablemente la única aplicación el usuario quiere no ser tocado. Estas consideraciones me insinúan que la política predeterminada del asesino OOM es demasiado agresiva. Utiliza un enfoque de "peor ajuste" que de alguna manera es similar al de algunos sistemas de archivos (el OOMK intenta y libera tanta memoria como puede, al tiempo que reduce el número de subprocesos muertos, para evitar cualquier intervención adicional en poco tiempo, ya que así como un fs puede asignar más espacio en disco del que realmente se necesita para un determinado archivo, para evitar cualquier asignación adicional si el archivo creció y, por lo tanto, previene la fragmentación, hasta cierto punto).

Sin embargo, creo que una política opuesta, como un enfoque de "mejor ajuste", podría ser preferible, por lo que liberar la memoria exacta que se necesita en un momento determinado y no molestar con procesos "grandes", que bien podrían estar desperdiciando memoria, pero también podría no serlo, y el kernel no puede saber eso (hmm, me imagino que mantener un registro del acceso a la página y el tiempo podría sugerir que si un proceso está asignando memoria ya no necesita más, así que adivinar si un proceso está desperdiciando memoria o simplemente está usando mucho, pero los retrasos de acceso deben ser ponderados en los ciclos de CPU para distinguir el desperdicio de memoria de una aplicación intensiva de memoria y CPU, pero, aunque potencialmente inexacto, dicha heurística podría tener una sobrecarga excesiva).

Además, podría no ser cierto que matar la menor cantidad de procesos posibles es siempre una buena elección. Por ejemplo, en un entorno de escritorio (pensemos en una nettop o una netbook con recursos limitados, por ejemplo), un usuario podría estar ejecutando un navegador con varias pestañas (por lo tanto, consume mucha memoria, supongamos que esta es la primera opción para el OOMK) , más algunas otras aplicaciones (un procesador de texto con datos no guardados, un cliente de correo, un lector de pdf, un reproductor multimedia, ...), más algunos demonios (del sistema), más algunas instancias de administrador de archivos. Ahora, ocurre un error OOM, y el OOMK elige matar el navegador mientras el usuario está haciendo algo que se considera 'importante' en la red ... el usuario se decepcionará. Por otro lado, cerrando los pocos administrador de archivos

De todos modos, creo que el usuario debería estar habilitado para tomar una decisión por sí mismo sobre qué hacer. En un sistema de escritorio (= interactivo), eso debería ser relativamente fácil de hacer, siempre que se reserven suficientes recursos para pedirle al usuario que cierre cualquier aplicación (pero incluso cerrar unas pocas pestañas podría ser suficiente) y manejar su elección (una opción podría consiste en crear un archivo de intercambio adicional, si hay suficiente espacio). Para los servicios (y en general), también consideraría otras dos mejoras posibles: una es registrar las intervenciones de OOM killer, así como los procesos que inician / bifurcan fallas de tal manera que la falla se pueda depurar fácilmente (por ejemplo, una API podría informar al proceso que emite la nueva creación o bifurcación del proceso; por lo tanto, un servidor como Apache, con un parche adecuado, podría proporcionar un mejor registro para ciertos errores); esto podría hacerse independientemente si el exceso de compromiso / OOMK está en esfuerzo; en segundo lugar, pero no por importancia, se podría establecer un mecanismo para ajustar el algoritmo OOMK: sé que es posible, hasta cierto punto, definir una política específica proceso por proceso, pero apuntaría a mecanismo de configuración 'centralizado', basado en una o más listas de nombres de aplicaciones (o identificadores) para identificar procesos relevantes y darles un cierto grado de importancia (según los atributos enumerados); dicho mecanismo también debería (o al menos podría) estar en capas, de modo que podría haber una lista definida por el usuario de nivel superior, una lista definida por el sistema (distribución) y entradas definidas por la aplicación (nivel inferior) , por ejemplo, un administrador de archivos DE podría indicarle a OOMK que elimine de forma segura cualquier instancia,

Además, se podría proporcionar una API para permitir que las aplicaciones aumenten o disminuyan su nivel de 'importancia' en tiempo de ejecución (con respecto a los propósitos de administración de memoria e independientemente de la prioridad de ejecución), de modo que, por ejemplo, un procesador de Word pueda comenzar con una 'importancia' baja, pero aumente a medida que se retengan algunos datos antes de pasar a un archivo, o se realice una operación de escritura, y vuelva a tener una importancia menor una vez que dicha operación termine (análogamente, un administrador de archivos podría cambiar el nivel cuando pasa de solo cargar archivos para tratar con datos y viceversa, en lugar de usar procesos separados, y Apache podría dar diferentes niveles de importancia a diferentes niños, o cambiar un estado secundario de acuerdo con alguna política decidida por los administradores de sistemas y expuesta a través de Apache, o cualquier otro tipo de servidor - ajustes). Por supuesto, tal API podría y sería maltratada / mal utilizada, pero creo que es una preocupación menor en comparación con el kernel que mata arbitrariamente los procesos para liberar memoria sin ninguna información relevante sobre lo que está sucediendo en el sistema (y el consumo de memoria / tiempo de creación o similares) es lo suficientemente relevante o 'validar' para mí): solo los usuarios, administradores y escritores de programas realmente pueden determinar si un proceso 'todavía es necesario' por alguna razón, cuál es la razón y / o si la aplicación está en un estado líder a pérdida de datos u otros daños / problemas si se mata; sin embargo, aún podría hacerse alguna suposición, por ejemplo, buscar recursos de un cierto tipo (descriptores de archivo, sockets de red, etc.) adquiridos por un proceso y con operaciones pendientes podría decir si un proceso debería estar en un 'estado' más alto que el conjunto

O simplemente evite comprometerse demasiado y deje que el kernel haga exactamente lo que debe hacer un kernel, asignando recursos (pero no rescatándolos arbitrariamente como lo hace el asesino OOM), programando procesos, previniendo hambrunas y puntos muertos (o rescatando de ellos), asegurando una prevención total y separación de espacios de memoria, etc.

También pasaría algunas palabras más sobre los enfoques de sobrecompromiso. De otras discusiones, he tomado la idea de que una de las principales preocupaciones sobre el exceso de compromiso (tanto como una razón para quererlo como una fuente de posibles problemas) consiste en el manejo de los tenedores: honestamente, no sé exactamente cómo se implementa la estrategia on-write, pero creo que cualquier política agresiva (u optimista) podría mitigarse mediante una estrategia de localidad de intercambio similar. Es decir, en lugar de simplemente clonar (y ajustar) páginas de códigos de proceso bifurcados y estructuras de programación, se podrían copiar algunas otras páginas de datos antes de una escritura real, eligiendo entre esas páginas a las que ha accedido el proceso principal para escribir con más frecuencia (es decir, usando un contador para operaciones de escritura).

Todo, por supuesto, en mi humilde opinión.


fuente
55
"Además, se podría proporcionar una API para permitir que las aplicaciones aumenten o disminuyan su nivel de 'importancia' en el tiempo de ejecución" /proc/$PID/oom_adj.
Vi.
1
Con respecto a la JVM, hay un problema que hace que desee un exceso de memoria en algunos casos: en caso de que desee crear otra JVM a partir de su JVM original, se llamará fork (). Una llamada fork asignará tanta memoria como el proceso original (primero), hasta que realmente comience el proceso. Así que usted tiene una JVM de 4 GB y desea crear una nueva máquina virtual Java 512 KB de ella, a menos que tenga overcommit, tendrá 8 GB de memoria para hacer eso ...
alci
44
@Vi. Parece que ahora es/proc/$PID/oom_score_adj
m3nda
1

Si su memoria se agota exhaustivamente por los procesos en la medida en que posiblemente pueda amenazar la estabilidad del sistema, entonces el asesino OOM aparece en la imagen. La tarea de OOM Killer es matar los procesos hasta que se libere suficiente memoria para el buen funcionamiento del resto del proceso. El OOM Killer tiene que seleccionar el "mejor" proceso para matar. "Mejor" aquí se refiere a ese proceso que liberará la memoria máxima al matar y también es menos importante para el sistema. El objetivo principal es matar el menor número de procesos que minimiza el daño hecho y al mismo tiempo maximiza la cantidad de memoria liberada. Para facilitar esto, el núcleo mantiene oom_score para cada uno de los procesos. Puede ver el oom_score de cada uno de los procesos en el sistema de archivos / proc en el directorio pid

# cat /proc/10292/oom_score

Cuanto mayor sea el valor de oom_score de cualquier proceso, mayor será su probabilidad de ser asesinado por el OOM Killer en una situación sin memoria.

Crédito: - El kernel de Linux está comenzando el asesino OOM

Dinkey Jhanwar
fuente