El uso de memoria en la compilación de Ember-cli corre el riesgo de fallar (OOM) en el tamaño mínimo de instancia

Durante la actualización, la mayor carga para la memoria (RAM+swap) se produce cuando se ejecuta el proceso ‘ember’. Creo que cada vez que he ejecutado una actualización, ha sido mayor que la anterior, y se está acercando a no poder ejecutarse en equipos con el tamaño mínimo recomendado.

Sería bueno investigar esto antes de que falle realmente. (Esperemos que, por razones de coste, la respuesta no sea aumentar el tamaño mínimo recomendado. Aumentar el swap ayudaría, si el espacio en disco lo permite. En principio, se podría migrar temporalmente a una instancia más cara con más RAM).

Ejecuto dos foros de tamaño modesto en instancias pequeñas, ambos dentro de los mínimos recomendados, creo. En ambos casos, RAM+swap=3G. En un caso, una instancia de Digital Ocean con 1G de RAM y 2G de swap, en el otro caso, una instancia de Hetzner con 2G de RAM y 1G de swap.

Aquí hay tres instantáneas del proceso ember, en la máquina DO, usando ps auxc

USER       PID %CPU %MEM      VSZ    RSS TTY   STAT START   TIME COMMAND
1000     10342 87.7 65.1 32930460 657936 ?     Rl   16:57   2:23 ember

USER       PID %CPU %MEM      VSZ    RSS TTY   STAT START   TIME COMMAND
1000     10342 84.9 60.7 43572204 612668 ?     Rl   16:57   2:57 ember

USER       PID %CPU %MEM      VSZ    RSS TTY   STAT START   TIME COMMAND
1000     10342 81.2 55.2 43405220 557128 ?     Rl   16:57   3:40 ember

Obviamente, el tamaño del proceso de 43 GB no está todo presente en la memoria virtual, ya que solo tenemos 3 GB disponibles. Usar el 65% del tamaño de la RAM para RSS es impresionante, pero no es un problema en sí mismo. La cantidad de memoria libre y swap libre muestra que la máquina está cerca de una condición de falta de memoria (OOM), lo que probablemente resultaría en que algún proceso sea eliminado y un final desordenado de la actualización.

Aquí está free como una instantánea puntual:

# free
              total        used        free      shared  buff/cache   available
Mem:        1009140      863552       72768        6224       72820       34868
Swap:       2097144     1160628      936516

Para intentar capturar la situación en su punto más cercano al fallo, usé vmstat 5

# 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
 3  0 1392140  61200  11632  76432    41    32   117    93    0     1  2  1 97  0  0
 1  1 1467220  63416    324  67284  8786 20499 13178 20567 2539  8924 77 13  0 10  0
 0  2 1593340  57916   1096  53832 24262 46868 29986 46889 5377 18534 44 22  0 34  0
 4  0 1155632 120680   2772  86280 39111 35424 54768 37824 6987 25174 38 27  0 35  0
 3  0 1102988  74096   2852  85276 11261   246 12610   271 1879  6365 86  6  0  8  0

Notarás muchos cambios de contexto (cs), mucha actividad de disco (bi, bo) y mucha actividad de swap (si, so), pero lo más importante es el uso de swap hasta 1.6G con la memoria libre hasta 60M y solo 54M de uso de búfer. Esto significa que aproximadamente 2.6G de los 3G disponibles de memoria virtual están en uso. Eso es el 87% de la capacidad. (Podría ser un poco peor, ya que solo tomamos muestras cada 5 segundos).

Tenga en cuenta que la situación era preocupante (con aproximadamente 2G de uso, no tan cerca del punto crítico como hoy) cuando actualicé en agosto:

# 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
 3  0  700404  62740   1956  48748    35    29   108    92    3     8  2  1 96  0  1
 1  0  741000  65996   1880  44360  3708 11190  3982 11191  643  1437 92  4  0  3  1
 1  0  834836  70452   1480  53856   528 18969  4274 18974  532  1575 93  6  0  1  0
 4  1 1010144  82192   4644  44400 30065 38803 35455 39946 4432 19267 28 26  0 39  7
 1  0  644116 307764   1644  55348 24406 21154 27724 21945 2551  8672 52 22  0 21  6
4 Me gusta

Hola @Ed_S: ¿qué versión de Discourse estabas usando para estas pruebas? Actualizamos regularmente ember-cli y sus complementos, así que solo quiero asegurarme de que estemos viendo lo mismo.

Además, ¿cuántos núcleos de CPU tienen tus VMs? ¿1? (puedes comprobarlo ejecutando lscpu en la consola).

Para que todos trabajemos con los mismos datos, ¿podrías intentar ejecutar:

/var/discourse/launcher enter app
cd /var/www/discourse/app/assets/javascripts/discourse
apt-get update && apt-get install time
NODE_OPTIONS='--max-old-space-size=2048' /usr/bin/time -v yarn ember build -prod

En mi droplet de prueba (1 CPU, 1 GB de RAM, 2 GB de swap), veo esto:

Comando que se está midiendo: "yarn ember build -prod"
	Tiempo de usuario (segundos): 369.74
	Tiempo de sistema (segundos): 22.62
	Porcentaje de CPU que obtuvo este trabajo: 81%
	Tiempo transcurrido (reloj de pared) (h:mm:ss o m:ss): 8:02.73
	Tamaño medio de texto compartido (kbytes): 0
	Tamaño medio de datos no compartidos (kbytes): 0
	Tamaño medio de pila (kbytes): 0
	Tamaño total medio (kbytes): 0
	Tamaño máximo del conjunto residente (kbytes): 774912
	Tamaño medio del conjunto residente (kbytes): 0
	Fallos de página importantes (que requieren E/S): 253770
	Fallos de página menores (recuperando un marco): 1158920
	Cambios de contexto voluntarios: 519269
	Cambios de contexto involuntarios: 383328
	Intercambios: 0
	Entradas del sistema de archivos: 7521784
	Salidas del sistema de archivos: 316304
	Mensajes de socket enviados: 0
	Mensajes de socket recibidos: 0
	Señales entregadas: 0
	Tamaño de página (bytes): 4096
	Estado de salida: 0

Estamos utilizando herramientas de ember bastante estándar aquí, así que no estoy seguro de que haya mucho que podamos hacer en términos de configuración para reducir el uso de memoria. Nuestro objetivo a largo plazo es pasar a usar Embroider, lo que podría darnos más opciones.

1 me gusta

Gracias @david, aprecio que Ember sea algo en sí mismo.

Acabo de ejecutar esos comandos.

# /var/discourse/launcher enter app
Se detectó la arquitectura x86_64.

ADVERTENCIA: Vamos a empezar a descargar la imagen base de Discourse
Este proceso puede tardar entre unos minutos y una hora, dependiendo de la velocidad de tu red

Por favor, ten paciencia

2.0.20220720-0049: Tirando de discourse/base
Digest: sha256:7ff397003c78b64c9131726756014710e2e67568fbc88daad846d2b368a02364
Estado: Imagen más nueva descargada para discourse/base:2.0.20220720-0049
docker.io/discourse/base:2.0.20220720-0049

Esta es una instalación de producción, por lo que, hasta ayer, estaba actualizada. Actualmente informa:

Instalado 2.9.0.beta12 (8f5936871c)

Es una instancia de un solo CPU, como la tuya, tiene 1 GB de RAM y 2 GB de swap.

El resultado del comando time fue

Hecho en 303.21s.

	Comando que se está cronometrando: "yarn ember build -prod"
	Tiempo de usuario (segundos): 222.71
	Tiempo de sistema (segundos): 17.17
	Porcentaje de CPU que obtuvo este trabajo: 78%
	Tiempo transcurrido (reloj de pared) (h:mm:ss o m:ss): 5:04.15
	Tamaño promedio de texto compartido (kbytes): 0
	Tamaño promedio de datos no compartidos (kbytes): 0
	Tamaño promedio de pila (kbytes): 0
	Tamaño total promedio (kbytes): 0
	Tamaño máximo del conjunto residente (kbytes): 702292
	Tamaño promedio del conjunto residente (kbytes): 0
	Fallos de página importantes (que requieren E/S): 348190
	Fallos de página menores (recuperando un marco): 1152689
	Cambios de contexto voluntarios: 617736
	Cambios de contexto involuntarios: 774189
	Swaps: 0
	Entradas del sistema de archivos: 5001936
	Salidas del sistema de archivos: 318280
	Mensajes de socket enviados: 0
	Mensajes de socket recibidos: 0
	Señales entregadas: 0
	Tamaño de página (bytes): 4096
	Estado de salida: 0

Inmediatamente antes, había actualizado el host y reiniciado, por lo que todo en el contenedor se habría reiniciado recientemente.

El peor uso de memoria, según lo informado por un vmstat ejecutándose en otra ventana:

# vmstat 1
procs  -----------memory----------    ---swap--  -----io----   -system-- ------cpu-----\n r  b    swpd   free   buff  cache    si     so    bi     bo    in    cs us sy id wa st\n 2  0  704000 136044  24136 158144  1517   3503  8256   4377   886  3564 43  8 43  6  0\n...\n 5  0 1451436  71604   1248  50196 55016 110236 73204 121060 13152 45971 29 60  0 10  1\n
2 Me gusta

Parece que aumentamos explícitamente la memoria asignable de Node de 500M a 2G. Posiblemente, esto sea un paso demasiado grande y 1.5G sería mejor:

Vale la pena señalar que Ember no es lo único que se ejecuta en la máquina, y estamos al límite global de RAM + swap. Por lo tanto, el historial de la máquina y las necesidades de todos los demás procesos en ejecución entran en juego. Mi reinicio podría haber ayudado aquí a alcanzar una marca de agua más baja en comparación con ayer.

La solicitud de extracción anterior se mencionó en
No se pudo actualizar la instancia de Discourse al 15 de febrero de 2022
donde también notamos que alguien tuvo una escasez de memoria que se resolvió con un reinicio.

Es una lástima que el comando time no informe el uso máximo de memoria. Posiblemente, en una máquina con al menos 3G de RAM y sin swap, el recuento de RSS nos diría el uso máximo de Ember. O posiblemente podríamos usar otra táctica: varias se describen aquí y hay algunas ideas aquí también.

Lo que es incómodo es que realmente estamos interesados en el uso de memoria aquí, mientras que en muchos casos las personas están interesadas en el uso de RAM, que es una pregunta diferente.

3 Me gusta

La razón por la que añadimos esa bandera fue que el propio asesino de OOM de Node estaba matando la compilación; 500M no era suficiente. Estaré encantado de intentar ajustarlo a 1.5G. Acabo de probarlo en mi droplet y parece que funciona bien. De hecho, parece que incluso 1.0G es suficiente.

Intenté rastrear el uso de memoria con diferentes tamaños de max_heap:

(while(true); do (free -m -t | grep Total | awk '{print $3}') && sleep 0.5; done) | tee 1000mb.csv

Muestra este uso durante la compilación:

Hubo muy poca diferencia en el tiempo de compilación, pero los límites de 1GB y 1.5GB claramente producen un menor uso general. Como se esperaba, la salida de time muestra significativamente menos “Fallos de página importantes” cuando el límite de Node es menor.

Es curioso que la diferencia entre 1.5GB y 1GB sea tan pequeña… :face_with_monocle:

En cualquier caso, estoy de acuerdo en que disminuir el límite es una buena idea. Para asegurarnos de que no afecte el rendimiento de la compilación en máquinas con especificaciones más altas, creo que solo deberíamos anular el límite cuando sepamos que es demasiado bajo. De lo contrario, podemos dejar que Node use su valor predeterminado.

Aquí hay una PR: intentaremos fusionarla pronto. ¡Gracias por plantear esto @Ed_S!

4 Me gusta

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.