Fragmentación de la memoria de Linux

20

¿Hay alguna manera de detectar la fragmentación de la memoria en Linux? Esto se debe a que en algunos servidores de larga ejecución he notado una degradación del rendimiento y solo después de reiniciar el proceso veo un mejor rendimiento. Lo noté más cuando uso el soporte de páginas enormes de Linux: ¿son las páginas enormes de Linux más propensas a la fragmentación?

He mirado / proc / buddyinfo en particular. Quiero saber si hay mejores formas (no solo los comandos CLI per se, cualquier programa o antecedentes teóricos lo harían) para verlo.

Raghu
fuente
No estoy buscando solo soluciones rápidas de línea de comandos, cualquier programa / teoría simple también lo hará. Por lo tanto, no pregunté en serverfault.
Raghu
1
No entiendo aquí un punto. Hasta donde entiendo, la fragmentación de la memoria debe conducir a la falta de memoria y, como resultado, a errores de asignación de memoria. Sin embargo, está preguntando acerca de la degradación del rendimiento. ¿Es porque tienes mucha memoria intercambiada en el disco? Y si es así, ¿qué dar vmstaten el campo so?
@skwllsp: edité mi respuesta para que sea más específica.
Tim Post
@Raghu: no esperaría que la mayoría de los administradores de sistemas modifiquen el código del kernel para que la administración de la memoria se comporte de manera diferente, sin embargo, los administradores expertos de Linux deberían conocer al menos una descripción general de cómo Linux administra la memoria. Esta pregunta está realmente en la línea. He votado para migrarlo simplemente porque no puedo sugerir (en mi respuesta) el código que responde a su pregunta. Leer desde / proc o usar vmstates una experiencia de usuario común. Si estuviera escribiendo un programa para hacer lo mismo, sería diferente. Si tiene la intención de usar bash para cosechar esta información, edite su pregunta, no se cerrará :)
Tim Post
@Tim: como sugerí, no solo quería saber los comandos bash / cli, necesitaba la información para ayudarme en mi procedimiento de evaluación comparativa (para analizar los resultados, no para ejecutarlos).
Raghu

Respuestas:

12

Estoy respondiendo a la etiqueta de . Mi respuesta es específica solo para Linux .

Sí, las páginas enormes son más propensas a la fragmentación. Hay dos vistas de memoria, la que obtiene su proceso (virtual) y la que administra el núcleo (real). Cuanto más grande sea una página, más difícil será agrupar (y mantener con) sus vecinos, especialmente cuando su servicio se ejecuta en un sistema que también tiene que admitir otros que, por defecto, asignan y escriben más memoria de la que ellos tienen. en realidad terminan usando.

La asignación del núcleo de direcciones (reales) otorgadas es privada. Hay una muy buena razón por la cual el espacio de usuario los ve como el núcleo los presenta, porque el núcleo debe poder comprometerse en exceso sin confundir el espacio de usuarios. Su proceso obtiene un espacio de direcciones "Disneyfied" agradable y contiguo en el que trabajar, ajeno a lo que el núcleo está haciendo realmente con esa memoria detrás de escena.

La razón por la que se ve el rendimiento sea menor en los servidores de larga ejecución es más probable porque los bloques asignados que no han sido bloqueados de forma explícita (por ejemplo mlock()/ mlockall()o posix_madvise()) y no modificada desde hace tiempo se han paginado , lo que significa que sus patines de servicios en el disco cuando se tiene que leer ellos. La modificación de este comportamiento hace que su proceso sea un mal vecino , por lo que muchas personas colocan su RDBMS en un servidor completamente diferente a web / php / python / ruby ​​/ lo que sea. La única forma de arreglar eso, sensatamente, es reducir la competencia por los bloques contiguos.

La fragmentación solo es realmente notable (en la mayoría de los casos) cuando la página A está en la memoria y la página B se ha movido para intercambiar. Naturalmente, reiniciar su servicio parecería "curar" esto, pero solo porque el núcleo aún no ha tenido la oportunidad de distribuir el proceso "(ahora) bloques recientemente asignados dentro de los límites de su relación de sobrecompromiso.

De hecho, reiniciar (digamos) 'apache' bajo una carga alta probablemente enviará bloques propiedad de otros servicios directamente al disco. Entonces, sí, 'apache' mejoraría por un corto tiempo, pero 'mysql' podría sufrir ... al menos hasta que el núcleo los haga sufrir por igual cuando simplemente hay una falta de memoria física suficiente.

Agregue más memoria o divida a los malloc()consumidores exigentes :) No es solo la fragmentación lo que debe estar observando.

Intenta vmstatobtener una visión general de lo que realmente se está almacenando y dónde.

Tim Post
fuente
Gracias por la respuesta. Estaba usando páginas enormes (tamaño = 2048 KB cada una) para mysql - pool de búferes innodb - para ver qué tan bien funciona (usando sysbench). Inicialmente, cuando el tiempo de actividad del proceso (e incluso el tiempo de actividad del sistema) era bajo, daba muy buenos resultados. Sin embargo, su rendimiento comenzó a degradarse en varias ejecuciones. Con respecto a la página que mencionó, seguramente noté una alta actividad de VM, pero supuse que podría haber sido debido al vaciado de registros de referencia y de innodb (actividad de VM más alta con páginas enormes que sin ellas). También configuré vm.swappiness en 1. No pude notar ningún cambio drástico.
Raghu
Según el excelente manual , "No se pueden intercambiar páginas enormes bajo presión de memoria". Creo que esta es una buena respuesta en la memoria estándar w / r / t, pero no para las grandes páginas.
Dan Pritts
5

Núcleo

Para obtener el índice de fragmentación actual, use:

sudo cat /sys/kernel/debug/extfrag/extfrag_index

Para desfragmentar la memoria del núcleo, intente ejecutar:

sysctl vm.compact_memory=1  

También intente desactivar Transparent Huge Pages (también conocido como THP) y / o deshabilitar el intercambio (o disminuir swappiness).

Espacio de usuario

Para reducir la fragmentación del espacio de usuario, es posible que desee probar un asignador diferente, por ejemplo jemalloc(tiene excelentes capacidades de introspección , lo que le dará una fragmentación interna del asignador).

Puede cambiar a malloc personalizado volviendo a compilar su programa con él o simplemente ejecutando su programa con LD_PRELOAD: LD_PRELOAD=${JEMALLOC_PATH}/lib/libjemalloc.so.1 app (tenga cuidado con las interacciones entre THP y los asignadores de memoria )

Aunque, ligeramente no relacionado con la fragmentación de la memoria (pero conectado a la compactación / migración de la memoria), probablemente desee ejecutar varias instancias de su servicio, una para cada nodo NUMA y vincularlas usando numactl.

SaveTheRbtz
fuente
1
¿Por qué crees que deshabilitar el intercambio podría ayudar? Para mí, parece más probable que deshabilitar el intercambio duela aún más.
kasperd
1
Debido a que no hay suficiente información en la publicación original, tal vez el proceso simplemente tenga fugas y comience a intercambiarse. Además, no veo ninguna razón legítima para usar el intercambio en prácticamente cualquier sistema de producción (mb solo para estaciones de trabajo compartidas para estudiantes).
SaveTheRbtz
2
Tener suficiente espacio de intercambio mejorará el rendimiento. Los problemas de rendimiento que obtendrá si no tiene suficiente espacio de intercambio es motivo suficiente para habilitar el intercambio.
kasperd
1
@SaveTheRbtz Una buena razón para usar el intercambio en un sistema de producción es que le da al sistema más opciones que usará solo si cree que son beneficiosas. Además, permite que las páginas modificadas a las que no se haya accedido en horas (y que nunca se pueda acceder) se expulsen de la preciosa memoria física. Por último, permite que el sistema maneje de manera sensata casos en los que se reserva mucha más memoria de la utilizada.
David Schwartz
2
"solo si cree que son beneficiosos", eso agrega heurística adicional y hace que el sistema sea menos predecible. También los algoritmos de reemplazo de página (utilizados en intercambio y anónimo mmap) se implementan de manera diferente en diferentes núcleos (por ejemplo, Linux vs FreeBSD), o incluso en diferentes versiones del mismo sistema operativo (2.6.32 vs 3.2 vs 3.10) ... "permite páginas modificadas [. ..] para ser expulsado de la [...] memoria física ", eso ocultará las pérdidas de memoria. "manejar casos en los que se reserva mucha más memoria de la utilizada": el sistema lento es mucho peor que el sistema inactivo, por lo que "cuerdo" es cuestionable.
SaveTheRbtz
4

El uso de páginas enormes no debería causar fragmentación de memoria adicional en Linux; El soporte de Linux para páginas grandes es solo para memoria compartida (a través de shmget o mmap), y cualquier página grande utilizada debe ser solicitada específicamente y previamente asignada por un administrador del sistema. Una vez en la memoria, se fijan allí y no se intercambian. El desafío de intercambiar páginas enormes frente a la fragmentación de la memoria es exactamente por qué permanecen ancladas en la memoria (al asignar una página enorme de 2 MB, el núcleo debe encontrar 512 páginas contiguas libres de 4KB, que incluso pueden no existir).

Documentación de Linux en páginas enormes: http://lwn.net/Articles/375098/

Hay una circunstancia en la que la fragmentación de la memoria podría hacer que la asignación de páginas grandes sea lenta (pero no donde las páginas grandes causen la fragmentación de la memoria), y eso es si su sistema está configurado para aumentar el grupo de páginas enormes si lo solicita una aplicación. Si / proc / sys / vm / nr_overcommit_hugepages es mayor que / proc / sys / vm / nr_hugepages, esto podría suceder.

jstultz
fuente
De hecho, y generalmente debería ayudar al rendimiento porque evitará fallas de TLB (consulte el artículo vinculado para obtener una explicación).
Dan Pritts
0

Hay /proc/buddyinfoque es muy útil. Es más útil con un buen formato de salida, como este script Python puede hacer:

https://gist.github.com/labeneator/9574294

Para páginas grandes, desea algunos fragmentos libres en el tamaño 2097152 (2MiB) o más grande. Para páginas grandes transparentes, se compactará automáticamente cuando se le pida al kernel, pero si desea ver cuántas puede obtener, entonces, como raíz, ejecute:

echo 1 | sudo tee /proc/sys/vm/compact_memory

También sí, las páginas enormes causan grandes problemas de fragmentación. O no puede obtener páginas grandes, o su presencia hace que el núcleo pase mucho tiempo extra tratando de obtener algunas.

Tengo una solución que me funciona. Lo uso en un par de servidores y mi computadora portátil. Funciona muy bien para máquinas virtuales.

Agregue la kernelcore=4Gopción a su línea de comando del kernel de Linux. En mi servidor uso 8G. Tenga cuidado con el número, porque evitará que su núcleo asigne cualquier cosa fuera de esa memoria. A los servidores que necesitan una gran cantidad de buffers de socket o que transmiten escrituras en disco a cientos de unidades no les gustará estar limitados de esta manera. Cualquier asignación de memoria que deba "anclarse" para losa o DMA está en esta categoría.

Toda la otra memoria se convierte en "móvil", lo que significa que se puede compactar en trozos agradables para una gran asignación de páginas. Ahora las grandes páginas transparentes realmente pueden despegar y funcionar como se supone que deben hacerlo. Cada vez que el núcleo necesita más páginas de 2M, simplemente puede reasignar páginas de 4K a otro lugar.

Y no estoy totalmente seguro de cómo interactúa esto con la E / S directa de copia cero. Se supone que la memoria en la "zona móvil" no está anclada, pero una solicitud directa de E / S haría exactamente eso para DMA. Podría copiarlo. De todos modos, podría fijarlo en la zona móvil. En cualquier caso, probablemente no sea exactamente lo que querías.

Zan Lynx
fuente