Solución 1:
Ajuste overcommit_ratio
a 80 probablemente no sea la acción correcta. Establecer el valor por debajo de 100 casi siempre es 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 sin usar allí mismo. Las aplicaciones hacen esto mucho, y para eso está diseñado el compromiso excesivo.
Entonces, básicamente, con un compromiso excesivo en 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 configurarla en un valor superior a 100 debido al escenario mencionado anteriormente, que es bastante común.
Ahora, en cuanto a su problema con la activación del asesino OOM, es probable que la configuración manual de compromiso excesivo no solucione esto. La configuración predeterminada (determinación heurística) es bastante inteligente.
Si desea ver si esta es realmente la causa del problema, mire /proc/meminfo
cuando el asesino OOM corre. Si ves que Committed_AS
está cerca de CommitLimit
, pero free
todavía muestra memoria libre disponible, entonces sí, puede ajustar manualmente la sobreasignación para su escenario. Establecer este valor demasiado bajo hará que el eliminador de OOM comience a eliminar aplicaciones cuando aún tenga suficiente memoria libre. Configurarlo demasiado alto puede hacer que las aplicaciones aleatorias se bloqueen cuando intentan usar la memoria que se les asignó, pero que en realidad no está disponible (cuando toda la memoria realmente se agota).
Solución 2:
La sección 9.6 "Exceso de compromiso y OOM" en el documento que @dunxd menciona es particularmente gráfica sobre los peligros de permitir el exceso de compromiso. Sin embargo, el 80
A mí también me pareció interesante, así que realicé algunas pruebas.
Lo que encontré es que el 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 de usuario normales.
Establecer la proporción en 100
o menos debe proporcionar la semántica clásica donde los valores de retorno de malloc/sbrk
son confiables Estableciendo proporciones inferiores a 100
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 intercambio deshabilitado, 9 GiB en uso, con top
mostrando
Mem: 24683652k total, 9207532k used, 15476120k free, 19668k buffers
Swap: 0k total, 0k used, 0k free, 241804k cached
Aquí hay algunos overcommit_ratio
la configuración y la cantidad de RAM que mi programa consumidor de RAM podría tomar (tocando cada página); en cada caso, el programa salió limpiamente una vez malloc
fallado.
50 ~680 MiB
60 ~2900 MiB
70 ~5200 MiB
100 ~12000 MiB
Ejecutar varios a la vez, incluso con algunos como usuario raíz, no cambió la cantidad total que consumieron juntos. Es interesante que no pudo consumir los últimos 3+ GiB más o menos; el free
no cayó mucho por debajo de lo que se muestra aquí:
Mem: 24683652k total, 20968212k used, 3715440k free, 20828k buffers
Los experimentos fueron complicados:todo lo que usa malloc en el momento en que toda la RAM está en uso tiende a fallar, ya que muchos programadores son terribles para verificar fallas de malloc en C, algunas bibliotecas de colección 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 más del 51% de la memoria disponible, necesitaba fork()
para exec()
algún programa de apoyo, por lo general uno mucho, mucho más pequeño. Los sistemas operativos con semántica de copia en escritura permitirían el 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 instanciarse como una nueva página independiente del enorme proceso inicial) terminaría muriendo. El proceso principal solo estaba en peligro si asignaba más memoria y podía manejar el agotamiento, en algunos casos simplemente esperando un poco a que otro proceso muriera y luego continuando. El proceso secundario generalmente se reemplazó a sí mismo con un programa (generalmente más pequeño) a través de exec()
y entonces estaba libre de la condición.
El concepto de overcommit de Linux es un enfoque extremo para permitir tanto el fork()
así como permitir que los procesos individuales se sobreasignen masivamente. Las muertes causadas por OOM-killer ocurren de forma asincrónica, incluso en programas que hacen manejar la asignación de memoria de manera responsable. Personalmente odio en todo el sistema overcommit en general y oom-killer en particular:fomenta un enfoque despreocupado de la gestión de la memoria que infecta las bibliotecas y, a través de ellas, todas las aplicaciones que las utilizan.
Sugeriría establecer la proporción en 100, y tener también una partición de intercambio que generalmente solo terminaría siendo utilizada por grandes procesos, que a menudo solo usan una pequeña fracción de la parte de ellos mismos que se mete en intercambio, y por lo tanto proteger la gran mayoría de los procesos de la falla OOM killer. Esto debería mantener su servidor web a salvo de la muerte aleatoria, y si fue escrito para manejar malloc
responsablemente, incluso a salvo de quitarse la vida (pero no apuestes por esto último).
Eso significa que estoy usando esto en /etc/sysctl.d/10-no-overcommit.conf
vm.overcommit_memory = 2
vm.overcommit_ratio = 100