vaciar memoria mejorar limpiar liberar gestion como cache ruby-on-rails linux memory unicorn ruby-2.0

ruby-on-rails - mejorar - memoria virtual linux mint



Cómo mejorar el intercambio de memoria entre procesos de unicornio con Ruby 2.0 en Linux (1)

Ruby 2.0 presenta un recolector de basura amistoso para copiar y escribir. Parece que mis procesos no mantienen la memoria compartida durante más de unos minutos; parece moverse bastante rápido de shared_dirty a private_dirty.

Algunos otros han tenido éxito haciendo que esto funcione:

Este programa se puede usar para verificar las estadísticas de memoria en Linux: https://gist.github.com/kenn/5105061

La configuración de mi unicornio: https://gist.github.com/inspire22/f82c77c0a465f1945305

Por alguna razón, mis aplicaciones de unicornio, también con preload_app = true, tienen mucha menos memoria compartida. Ruby 2.0-p195, rieles 3.2, linux 2.6.18 (centos)

[root@thorn script]# ruby memstats.rb 4946 Process: 4946 Command Line: unicorn_rails worker[4] -c /u/apps/newap/current/lib/unicorn.rb -E production -D Memory Summary: private_clean 0 kB private_dirty 56,324 kB pss 60,256 kB rss 83,628 kB shared_clean 4,204 kB shared_dirty 23,100 kB size 108,156 kB swap 68 kB

Si cierro por completo el proceso maestro (no solo un HUP), lo reinicio y verifico inmediatamente a un trabajador antes de que las solicitudes hayan sido puestas en cola, obtengo una mejor historia:

[root@thorn script]# ruby memstats.rb 5743 Process: 5743 Command Line: unicorn_rails worker[4] -c /u/apps/newap/current/lib/unicorn.rb -E production -D Memory Summary: private_clean 0 kB private_dirty 21,572 kB pss 27,735 kB rss 66,296 kB shared_clean 2,484 kB shared_dirty 42,240 kB size 91,768 kB swap 0 kB

Pero dentro de los 5 segundos de haberse iniciado, han vuelto a ~ 20MB de shared_clean + shared_dirty.

Sospeché que el intercambio podría estar causando el problema, pero después de reducir la confusión y asegurarme de que ni los procesos primarios ni secundarios se intercambian (utilizando swapstats.rb), el problema persiste.

No entiendo exactamente qué es la memoria shared_dirty, y cómo se convierte en memoria privada. También me encantan las sugerencias para mejorar la longevidad y la cantidad de mi memoria compartida. ¡Gracias!


De acuerdo con esta respuesta , que ya puede haber visto, hay una línea que dice:

Tenga en cuenta que una página "compartida" se cuenta como una asignación privada hasta que realmente se comparta. es decir, si solo hay un proceso que utiliza libfoo actualmente, la sección de texto de esa biblioteca aparecerá en las asignaciones privadas del proceso. Se contabilizará en las asignaciones compartidas (y se eliminará de las privadas) solo si / cuando otro proceso comienza a usar esa biblioteca.

Lo que haría para probar si obtiene los beneficios descritos en este artículo , es poner un archivo de 10MB xml como una cadena literal directamente en su código fuente. Luego, si activa 20 trabajadores, podrá ver si está usando 200 MB de memoria, o solo 10 MB, como se espera con la nueva función de recolección de elementos no utilizados.

ACTUALIZAR:

Estaba buscando en la fuente del unicornio y encontré una referencia a este maravilloso artículo .

Para resumir, indica que para adaptar sus aplicaciones para aprovechar el recolector de basura amistoso copy-on-write de Ruby Enterprise Edition, debe establecer GC.copy_on_write_friendly como verdadero antes de que se bifurque .

if GC.respond_to?(:copy_on_write_friendly=) GC.copy_on_write_friendly = true end

Según el archivo de configuración de unicornio provisto, parece que falta la tarea.

Además, disfruté leyendo estos artículos relacionados:

De acuerdo con la http://linux.die.net/man/2/fork :

En Linux, fork () se implementa utilizando páginas de copia sobre escritura, por lo que la única penalización en la que incurre es el tiempo y la memoria necesarios para duplicar las tablas de página de los padres y crear una estructura de tareas única para el niño.

Desde la versión 2.3.3 , en lugar de invocar la llamada al sistema fork () del núcleo, el envoltorio glibc fork () que se proporciona como parte de la implementación de subprocesamiento NPTL invoca clone (2) con indicadores que proporcionan el mismo efecto que la llamada al sistema tradicional . (Una llamada a fork () es equivalente a una llamada a clonar (2) especificando flags como solo SIGCHLD.) El contenedor glibc invoca cualquier manejador de fork que se haya establecido usando pthread_atfork (3).

Y de acuerdo con la http://linux.die.net/man/2/clone :

A diferencia de fork (2), estas llamadas permiten que el proceso secundario comparta partes de su contexto de ejecución con el proceso de llamada, como el espacio de memoria, la tabla de descriptores de archivos y la tabla de controladores de señal.

Así que, estoy leyendo esto para decir: el fork-write-write de linux, que es la característica en la que unicornio se basa para implementar el uso compartido de memoria, no se implementó hasta que libc 2.2.3 (por favor, alguien me corrija si me equivoco en esta interpretación).

Para verificar qué versión de libc está ejecutando, puede escribir:

ldd --version

O bien, encuentre glibc y ejecútelo directamente. En mi sistema encontró el archivo en la siguiente ubicación:

locate libc.so /lib/x86_64-linux-gnu/libc.so.6