Node, como tiempo de ejecución de Javascript en el lado del servidor, enriquece enormemente los escenarios de aplicación de Javascript.
Sin embargo, Node.js Runtime en sí es un cuadro negro. No podemos percibir el estado del tiempo de ejecución y es difícil reproducir los problemas en línea.
Por lo tanto, la supervisión del rendimiento es la piedra angular del "funcionamiento normal" de las aplicaciones Node.js. No solo se pueden monitorear varios indicadores de tiempo de ejecución en cualquier momento, sino que también puede ayudar a solucionar problemas de escenarios anormales.
El monitoreo del rendimientose puede dividir en dos partes:
recopilación y visualización de indicadores de rendimiento
captura y análisis de datos de rendimiento
como QPS, HTTP lento, registros de enlaces de procesamiento empresarial, etc.En la imagen de arriba, puede ver las ventajas y desventajas de las tres soluciones actuales de monitoreo de rendimiento de Node.js. La siguiente es una breve introducción a la composición de estas tres soluciones:
Prometheus
AliNode de circuito cerrado.
Alinode es un tiempo de ejecución extendido compatible con nodejs oficiales, que proporciona algunas funciones adicionales:
Agenthub es un proceso residente que se utiliza para recopilar indicadores de rendimiento e informar sobre ellos.
forman un circuito cerrado desde el monitoreo, la visualización, la instantánea y el análisis. El acceso es conveniente y simple, pero aún existen riesgos al expandir el tiempo de ejecución
Easy-Monitor
Node.js Addon
para implementar elLos datos de consumo de tiempo de CPU del proceso actual se pueden obtener a través de process.cpuUsage()
La unidad del valor de retorno es microsegundos.
Los datos de asignación de memoria del proceso actual se pueden obtener a través de process.memoryUsage()
. La unidad del valor de retorno es bytes
Como se puede ver en la figura anterior, rss
incluye segmento de código ( Code Segment
), memoria de pila ( Stack
) y memoria de montón ( Heap
).
Puede obtener datos de análisis de la memoria y el espacio del montón de v8 a través de v8.getHeapStatistics()
y v8.getHeapSpaceStatistics()
La siguiente figura muestra la distribución de la composición de la memoria del montón de v8:
El espacio de la memoria del montón primero se divide en espacios y el espacio se divide en páginas. La memoria se pagina según una alineación de 1 MB.
Nuevo espacio: espacio de nueva generación, utilizado para almacenar algunos datos de objetos con un ciclo de vida relativamente corto, dividido en dos espacios (el tipo de espacio es semi space
): from space
to space
Espacio antiguo : el espacio de generación anterior, utilizado para almacenar objetos promovidos por New Space
Code Space: almacena el código ejecutable compilado por v8 JIT.
Map Space: almacena el objeto puntero de la clase oculta apuntada por Object. v8 según el tiempo de ejecución La estructura de diseño de objetos se utiliza para acceder rápidamente a miembros de objetos.
Espacio de objetos grandes: se utiliza para almacenar objetos de más de 1 MB que no se pueden asignar a páginas.
El algoritmo de recolección de basura de
Mark-Sweep-Compact
Minor GC para el reciclaje de objetos en la generación anteriorScavenge
se utiliza para reciclar objetos en la nueva generaciónPremisa: New space
se divide en dos espacios de objetos: from
y to
Tiempo de activación: cuando New space
está lleno.
Pasos:
en from space
, realice un recorrido en amplitud
y descubra que el objeto superviviente (alcanzable)
Old space
yto space
Cuando finaliza la copia, solo quedan objetos supervivientes en to space
, from space
se vacía,
se intercambia from space
to space
y comienza la siguiente ronda Scavenge
.
es adecuado para reciclaje frecuente y memoria insuficiente Para objetos grandes, la estrategia típica de espacio por tiempo tiene la desventaja de desperdiciar el doble de espacio que
Tres pasos: marcar, borrar y organizar
. Tiempo de activación: cuando Old space
está lleno.
Pasos:
Marcar (método de marcado de tres colores).
marking queue
(pila explícita) y márquelos en gris.pop
el objeto de marking queue
y márquelo en negro.push
a marking queue
.barrido
del montón. El barrido compacto
Old space
, para que el espacio limpiado sea continuo y completo.Cuando v8 realiza inicialmente la recolección de basura, necesita detener el programa, escanear todo el montón y recuperar la memoria antes de volver a ejecutar el programa. Este comportamiento se denomina pausa completa ( Stop-The-World
).
Aunque los objetos activos en la nueva generación son pequeños y se reciclan con frecuencia, un punto final tiene poco impacto. Sin embargo, los objetos supervivientes en la generación anterior son muchos y grandes. y pausas provocadas por marcar, limpiar, clasificar, etc. Será más grave.
Este concepto es en realidad un poco como la arquitectura Fiber en el marco React. Solo durante el tiempo libre del navegador atravesará el Fiber Tree para realizar las tareas correspondientes, de lo contrario, la ejecución se retrasará, afectando lo menos posible las tareas del hilo principal. , evitando retrasos en las aplicaciones y mejorando el rendimiento de las mismas.
Porque v8 tiene un límite predeterminado en el espacio de las generaciones nuevas y antiguas.
New space
: 32 M para sistemas de 64 bits y 16 M para sistemas de 32 bitsOld space
700M para sistemas de 32 bitsPor lo tanto, node
Se proporcionan dos parámetros para ajustar el límite de espacio superior de las generaciones nueva y antigua
--max-semi-space-size
: establece el valor máximo del espacio New Space
--max-old-space-size
: establece el valor máximo de la vista de espacio Old Space
node
de registro de GC también proporciona tres formas de ver los registros de GC:
--trace_gc
: una línea de registro describe brevemente el tiempo, el tipo, los cambios en el tamaño del montón y las causas de cada GC--trace_gc_verbose
: muestra cada montón V8 después de cada GC Estado detallado del espacio--trace_gc_nvp
: información detallada del par clave-valor de cada GC, incluido el tipo de GC, tiempo de pausa, cambios de memoria, etc.Dado que el registro de GC es relativamente primitivo y requiere procesamiento secundario, puede usar v8-gc, desarrollado por el equipo de AliNode, la
toma una instantánea de la memoria del montón de un programa en ejecución y se puede usar para analizar el consumo de memoria y cambiar
.heapsnapshot
generarse de las siguientes maneras:
usando heapdump
Usando el perfil de montón de v8
v8.getHeapSnapshot()
proporcionada por el módulo v8 integrado de nodejs
v8.writeHeapSnapshot(fileName)
Usando v8-profiler-siguiente
.heapsnapshot
cargar en la Memoria en la barra de herramientas de desarrollo de Chrome y los resultados se mostrarán como se muestra a continuación:
La vista predeterminada es Summary
. Aquí debemos prestar atención a las dos columnas de la derecha: Shallow Size
y Tamaño Retained Size
Retained Size
Shallow Size
el tamaño del objeto asignado en la memoria del montón v8.Shallow Size
de todos los objetos referenciados del objeto.Cuando se descubre que Retained Size
es particularmente grande, puede haber una pérdida de memoria dentro del objeto. Puede expandirse aún más para localizar el problema
Comparison
Analice las instantáneas del montón de dos períodos diferentes. La columna Delta
se puede utilizar para filtrar los objetos con los mayores cambios de memoria.
realiza un muestreo de instantáneas de la CPU que ejecuta el programa, que se puede utilizar para analizar el tiempo y la proporción de la CPU.
Hay varias formas de generar un archivo .cpuprofile
:
Esta es una colección de muestra de perfil de CPU de 5 minutos
El archivo .cpuprofile
generado Javascript Profiler
La vista predeterminada es la vista Heavy
. Aquí vemos dos columnas: Self Time
y Total Time
Self Time
representa el tiempo de ejecución de esta función en sí (excluyendo otras llamadas).Total Time
: representa el tiempo de ejecución de esta función (incluidas otras)Total Time
Self Time
un cálculo intensivo de la CPU que lleva mucho tiempo. También puede realizar más soluciones a los problemas
la aplicación falla y finaliza
.el sistema lo registrará automáticamente. El proceso bloquea la información de asignación de memoria, el contador de programa, el puntero de la pila y otra información clave en ese momento para generar
. Tres métodos para generar archivos .core
:
ulimit -c unlimited
abre el límite del kernel.node --abort-on-uncaught-exception
Agregar este parámetro al iniciar el nodo puede generar un archivo principal cuando ocurre una excepción no detectada en la aplicacióngcore <pid>
Generar manualmente. Después de obtener el archivo .core
, analice y El diagnóstico se puede lograr a través de herramientas como mdb, gdb, lldb, etc. La causa real del bloqueo del proceso
llnode `which node` -c /path/to/core/dump
A partir del monitoreo se puede observar que la memoria del montón continúa aumentando, por lo que se necesitan instantáneas del montón para la resolución de problemas
Según heapsnapshot
podemos analizar y descubrir que hay un objeto newThing
que siempre ha mantenido una memoria relativamente grande
unused
theThing
newThing
. Los casos replaceThing
causados por cierres
incluyen las siguientes situaciones:
Por lo tanto, en las situaciones anteriores, debe considerar cuidadosamente si el objeto en la memoria se reciclará automáticamente. no se puede reciclar automáticamente, es necesario el reciclaje manual, como configurar manualmente los objetos en null
, eliminar temporizadores, desvincular detectores de eventos, etc.
este artículo. Este artículo ha brindado una introducción detallada a todo el sistema de monitoreo de rendimiento de Node.js.
Primero, presenta los problemas resueltos por el monitoreo del desempeño, sus componentes y una comparación de las ventajas y desventajas de las soluciones convencionales.
Luego, se presentan en detalle las dos partes principales de los indicadores de rendimiento y las herramientas de instantáneas.
Finalmente, se reproduce un caso simple de pérdida de memoria a partir de la observación, el análisis y la resolución de problemas, y se resumen situaciones y soluciones comunes de pérdida de memoria.
Espero que este artículo pueda ayudar a todos a comprender todo el sistema de monitoreo del rendimiento de Node.js.