¿Pitchfork está usando demasiada memoria?

¿Alguien más ve esto? Es un foro bastante modesto en tamaño y tráfico. Hay cuatro procesos de trabajo de pitchfork, y parece que uno de ellos maneja la gran mayoría de las solicitudes entrantes y está usando más memoria que los demás. Hay mucho uso de swap, y al reiniciar deliberadamente pitchfork, esto se reduce considerablemente. Por lo tanto, concluyo que los procesos de pitchfork tienen muchas páginas frías actualmente intercambiadas a swap.

Esto es después de 20 días de funcionamiento, en una máquina con 4 GB de RAM y 4 GB de swap.

No sería bueno quedarse sin swap. Tampoco sería bueno encontrar que todo ese swap se esté paginando de nuevo a la memoria, como podría suceder eventualmente cuando pitchfork realice una recolección de basura.

¿Alguien más ve algo similar? ¡Por favor, compartan la configuración de su máquina!

# ps aux | sort -n -k 4 | egrep pitchf\|MEM |tail
root     2167652  0.0  0.0   5912  1792 pts/0    S+   20:07   0:00 grep -E --color=auto pitchf|MEM
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000       15094  0.0  0.2 497544 10988 ?        Sl   Jul28   0:17 pitchfork monitor - 
1000       15704  0.0  2.5 6799124 97836 ?       Sl   Jul28   1:00 pitchfork (gen:0) service - ready
1000       15097  0.0  4.8 6791252 189724 ?      Sl   Jul28   5:26 pitchfork (gen:0) mold - ready
1000       15959  0.0  8.1 6815508 319708 ?      Sl   Jul28  12:05 pitchfork (gen:0) worker[3] - requests: 6684, waiting
1000       15900  0.0  9.2 6864596 360696 ?      Sl   Jul28  17:43 pitchfork (gen:0) worker[2] - requests: 14756, waiting
1000       15795  0.1 10.3 6884756 405420 ?      Sl   Jul28  48:36 pitchfork (gen:0) worker[1] - requests: 97007, waiting
1000       15734  2.1 12.8 11299708 500120 ?     Sl   Jul28 637:50 pitchfork (gen:0) worker[0] - requests: 2229848, waiting

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1874636       98840      678812     1931492     1160916
Swap:        4194288     1226600     2967688


# vmstat 5 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0 1226600 115820  65288 1866284    1    1    20    38    0    3  3  1 97  0  0
 0  0 1226600 113208  65296 1866296    0    0     0    14  411  478  1  1 98  0  0
 0  0 1226600 112956  65304 1866336    0    0     1    23  438  528  2  1 97  0  0
 0  0 1226600 112704  65308 1866360    0    0     1    31  518  603  5  1 94  0  0
 0  0 1226600 112704  65308 1866364    0    0     0    11  347  387  1  1 98  0  0

La salida de vmstat muestra que actualmente no hay presión de memoria: no hay actividad de paginación. Mi preocupación es que existe un peligro, no que mi instalación esté funcionando mal en este momento.

cpu0

En un tono más serio, ¿el que está haciendo todo el trabajo solo tiene 100 MB de RSS por encima del promedio? Me parece normal, o ¿se me está escapando algo?

Me interesaría ver las estadísticas de un foro con más actividad. Parece que el número acumulado de solicitudes es importante, y el mío no es nada activo.

Sí, las diferencias en RSS son relativamente modestas, pero al ir de 300M a 500M hay una diferencia bastante grande en proporción.

Aún más llamativa es la utilización de swap. Antes de reciclar, veo:

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1888140       77308      679004     1939520     1147220
Swap:        4194288     1226344     2967944

y después:

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1486412     1422380      640744      996176     1587908
Swap:        4194288      309892     3884396

A mí me parece que se liberaron 1300M al reciclar (diferencia de used+swap)

No creo que viera tanta necesidad de swap al usar unicorn: de ahí el título.

Como digo, me interesa ver números de otras instancias.

Es normal que un proceso de pitchfork asuma la mayor parte de la carga; los demás procesos solo se seleccionan cuando el primero está ocupado. También es normal que la memoria crezca con el tiempo. Aunque debería alcanzar un estado estable eventualmente, una vez que todo, como las cachés y ruby-JIT, esté «calentado».

Aquí hay un gráfico de uno de nuestros clústeres de producción, durante un período de 7 días. Este rastrea el proceso individual con el mayor uso de memoria. Las líneas punteadas de color verde indican despliegues (es decir, reinicios frescos de pitchfork):

Así que puedes ver que sí crece después del lanzamiento inicial, pero luego se estabiliza en poco menos de 1.4 GB. Este clúster sirve a cientos de sitios, por lo que quizás no sea la mejor comparación en términos de números… pero espero que la visualización del crecimiento sea útil.

Mirar los números de RSS por proceso no cuenta toda la historia. Pitchfork es un «servidor web que realiza fork». Así que arranca el proceso «molde» (mold) y luego todos los trabajadores (workers) se bifurcan de él con un patrón de memoria de copia bajo escritura (copy-on-write). Por lo tanto, aunque el RSS podría mostrar 500 MB para worker[0], aproximadamente 200 MB de eso están compartidos con el molde y todos los demás trabajadores.

En un futuro no muy lejano, esperamos habilitar la función de «reforking» de Pitchfork. Esto mata periódicamente a los trabajadores y vuelve a bifurcarlos desde un trabajador ya calentado, para que compartan la mayor cantidad de memoria posible con el tiempo. Sin embargo, se necesita algo de trabajo para asegurarse de que todo nuestro código sea compatible con ese tipo de patrón :crossed_fingers:

Visualización muy útil, gracias. No diría que se haya estabilizado, pero la tasa de crecimiento no es tan alta como antes.

El reforking periódico suena como algo genial para implementarlo. Si es posible, por favor, indícalo aquí cuando se implemente.

¿Puedes decir algo sobre las líneas verdes? Me interesa saber cuándo (si es que alguna vez) los pitchforks realizan una recolección de basura, qué lo provoca y cuál es el efecto mientras la están realizando.

Las líneas verdes indican cuándo desplegamos actualizaciones. En esencia: ./launcher rebuild app.

Ruby (y JS, que se ejecuta dentro de los procesos de Ruby mediante MiniRacer/v8) recogen basura constantemente mientras están en ejecución y en respuesta a señales del sistema operativo. Por lo tanto, no creo que haya ningún gran beneficio en hacerlo manualmente.

Gracias. Me interesaría ver cómo evolucionan las cosas a largo plazo, algo que no será evidente en un servidor que se actualiza con relativa frecuencia. En mi caso, tuve 20 días y luego opté por usar pitchfork para reiniciar, lo cual me dio cierta información, pero también reinició el contador.