Conocemos a Node.js por su rápido rendimiento. Sin embargo, como con cualquier lenguaje, puedes escribir código Node.js que se desempeñe peor para tus usuarios de lo que te gustaría. Para combatir esto, necesitamos pruebas de rendimiento adecuadas. Hoy, vamos a cubrir precisamente eso con una mirada en profundidad sobre cómo configurar y ejecutar una prueba de rendimiento y analizar los resultados para que pueda hacer aplicaciones Node.js relámpago.
La mejor manera de entender cómo probar el rendimiento de su aplicación es caminar a través de un ejemplo.
Puede utilizar Node.js para muchos propósitos: escribir scripts para ejecutar tareas, ejecutar un servidor web, o servir archivos estáticos, como un sitio web. Hoy, recorreremos los pasos para probar una API web HTTP de Node.js. Pero si estás construyendo algo más en Node, no te preocupes-muchos de los principios serán similares.
- La naturaleza única del rendimiento de Node.js
- El bucle de eventos
- El rendimiento de Node.js y el bucle de eventos
- Paso 1: Elegir las herramientas de prueba de rendimiento de Node.js
- Paso 2: Crear un perfil de prueba de rendimiento de Node.js
- Aprovechando múltiples perfiles de prueba
- Replicando sistemas distribuidos a gran escala
- Paso 3: Configurar la observabilidad/monitorización
- Ponerse en marcha con un APM
- Herramientas adaptadas a Node.js
- Paso 4: Crear la infraestructura de pruebas de rendimiento de Node.js
- Paso 5: Ejecutar sus pruebas!
- Ahora tienes Node.js
La naturaleza única del rendimiento de Node.js
Antes de empezar, echemos un vistazo rápido a una de las características más únicas del rendimiento de Node.js. Necesitaremos tener conocimiento de estas características más tarde cuando ejecutemos nuestras pruebas de rendimiento.
¿De qué estoy hablando?
La gran consideración para las aplicaciones Node.js es su comportamiento de un solo hilo, de ejecución hasta el final-facilitado por lo que se conoce como el bucle de eventos. Ahora, sé lo que estás pensando: eso es mucho. Así que vamos a desglosar esto un poco para que entendamos lo que significan.
Comencemos con el hilo único. El threading, como concepto, permite el procesamiento concurrente dentro de una aplicación. Node.js no tiene esta capacidad, al menos no en el sentido tradicional. En su lugar, para escribir aplicaciones que realicen múltiples tareas a la vez, tenemos el código asíncrono y el bucle de eventos.
El bucle de eventos
¿Qué es el bucle de eventos?
El bucle de eventos es la forma que tiene Node.js de dividir los procesos de larga duración en pequeños trozos. Funciona como un latido del corazón: Cada pocos milisegundos, Node.js comprobará una cola de trabajo para iniciar nuevas tareas. Si hay trabajo, las traerá a la pila de llamadas y las ejecutará hasta completarlas (pronto hablaremos de la ejecución hasta completarlas).
Al dividir las tareas, Node.js puede realizar multitareas, que es su sustituto de los hilos. Esto significa que mientras una tarea está esperando, otra puede comenzar. Así que, en lugar de hilos, usamos código asíncrono, facilitado por estilos de programación como callbacks, promesas y async/await. La mayoría de las APIs de Node tienen tanto un método de ejecución síncrono como asíncrono.
De acuerdo, así que quizás te estés preguntando: ¿qué tiene que ver toda esta jerga tecnológica con el rendimiento?
Déjame que te lo explique…
El rendimiento de Node.js y el bucle de eventos
Imagina que estás construyendo una aplicación Node.js con dos endpoints: uno para subir archivos, y otro que recupera un perfil de usuario. La API de perfil de usuario probablemente se solicitará con mucha más frecuencia que la subida de archivos, y si no responde lo suficientemente rápido, bloqueará cada carga de la página para cada usuario – no es bueno.
La API de subida de usuarios se utiliza con poca frecuencia. Además, los usuarios esperan que la carga de tareas lleve tiempo, pero son mucho menos indulgentes con los tiempos de carga de la página. Si no programamos con el bucle de eventos en mente, mientras el archivo se está cargando, Node.js podría terminar acaparando todos los recursos del sistema y podría bloquear a otros usuarios de usar su aplicación-¡uh-oh!
Y es por eso que necesitas entender la naturaleza de un solo hilo de Node.js. A medida que cambiamos nuestra aplicación, tenemos que considerar este comportamiento. Queremos evitar hacer tareas de larga duración de forma sincrónica, como hacer peticiones a la red, escribir archivos o realizar un cálculo pesado.
Ahora que conocemos la naturaleza single-threaded de Node.js, podemos usarla a nuestro favor. Vamos a ir paso a paso cómo se puede configurar, ejecutar y analizar una prueba de rendimiento de su aplicación Node.js para asegurarse de que está haciendo todo lo posible para aprovechar las capacidades de rendimiento de Node.js.
Paso 1: Elegir las herramientas de prueba de rendimiento de Node.js
En primer lugar, usted querrá elegir una herramienta que le permitirá ejecutar sus pruebas de rendimiento. Hay muchas herramientas por ahí, todas con diferentes pros y contras para el ajuste del rendimiento de Node.js. Una cosa principal a considerar es que a pesar de que estás probando una aplicación Node.js si vas a probar el rendimiento desde el mundo exterior a través de una red, no importa si tu herramienta de prueba de rendimiento está escrita en Node.js.
Para las pruebas básicas de rendimiento HTTP, me gusta Artillery una herramienta de prueba de rendimiento directa escrita en Node.js. También es particularmente bueno en la ejecución de pruebas de rendimiento para las solicitudes de la API. Artillery funciona escribiendo un archivo de configuración que define su perfil de carga. Le dices a Artillery qué puntos finales quieres solicitar, a qué ritmo, por qué duración, etc.
Un script de prueba básico se parece a esto:
config: target: 'https://artillery.io' phases: - duration: 60 arrivalRate: 20 defaults: headers: x-my-service-auth: '987401838271002188298567'scenarios:- flow:- get:url: "/docs"
Aquí, estás solicitando el sitio web de Artillery por una duración de 60 segundos con 20 nuevos usuarios que llegan a la URL.
Entonces, para ejecutar la prueba, simplemente ejecuta:
artillery run your_config.yml
Artillery hará tantas peticiones a tu aplicación como le hayas indicado. Esto es útil para construir perfiles de prueba de rendimiento que imitan su entorno de producción. ¿Qué quiero decir con perfil de prueba de rendimiento? Vamos a cubrir eso ahora.
Paso 2: Crear un perfil de prueba de rendimiento de Node.js
Un perfil de prueba de rendimiento, como arriba, es una definición de cómo se ejecutará su prueba de rendimiento. Querrás imitar cómo se comporta, o se espera que se comporte, tu tráfico de producción, si es posible para hacer un ajuste preciso del rendimiento de Node.js. Por ejemplo, si estás construyendo un sitio web de eventos, esperarías mucho tráfico alrededor del momento en que liberas las entradas, así que querrías construir un perfil que imite este comportamiento. Querrás probar la capacidad de tu aplicación para escalar con grandes cantidades de carga en un corto período de tiempo. Por otra parte, si está ejecutando un sitio de comercio electrónico, podría esperar un tráfico uniforme. Aquí, sus perfiles de prueba de rendimiento deben reflejar este comportamiento.
Aprovechando múltiples perfiles de prueba
Un punto divertido e interesante a tener en cuenta es que usted puede crear diferentes perfiles de prueba y ejecutarlos de manera superpuesta. Por ejemplo, puede crear un perfil que imite su nivel básico de tráfico -por ejemplo, 100 solicitudes por minuto- y luego imitar lo que podría suceder si viera mucho tráfico en su sitio, por ejemplo, si pusiera algunos anuncios en los motores de búsqueda. Probar múltiples escenarios es importante para un ajuste exhaustivo del rendimiento de Node.js.
Replicando sistemas distribuidos a gran escala
Debo tomarme un segundo aquí para señalar algo: Cuando una aplicación alcanza un cierto tamaño, imitar la carga de esta manera pierde viabilidad. Los volúmenes de tráfico que puedes tener podrían ser tan salvajes, impredecibles o de gran volumen que es difícil crear una forma realista de probar tu aplicación antes del lanzamiento.
¿Pero qué pasa si este es el caso? ¿Qué hacemos? Probamos en producción.
Podrías pensar, «¡Woah, espera! ¿No se supone que debemos probar antes de la liberación?»
Puede, pero cuando un sistema llega a un cierto tamaño, podría tener sentido para aprovechar diferentes estrategias de prueba de rendimiento. Puedes aprovechar conceptos como la liberación canaria para poner tus cambios en producción y probarlos sólo con un cierto porcentaje de usuarios. Si observa una disminución del rendimiento, puede volver a cambiar ese tráfico a su implementación anterior. Este proceso realmente fomenta la experimentación, y la mejor parte es que usted está probando en su aplicación de producción real, por lo que no se preocupa por los resultados de las pruebas no imitan la producción.
Hasta ahora hemos decidido sobre nuestra herramienta, y hemos creado perfiles que recrean nuestra producción, como el tráfico y las cargas de trabajo. ¿Qué hacemos ahora? Tenemos que asegurarnos de que tenemos los datos que necesitamos para analizar nuestra aplicación, y lo hacemos a través de la monitorización del rendimiento de Node.js y las herramientas de gestión del rendimiento de las aplicaciones (APM). ¿Qué es un APM? Sigue leyendo y te lo contaré!
Paso 3: Configurar la observabilidad/monitorización
No queremos limitarnos a ejecutar nuestro test de rendimiento contra nuestra aplicación y esperar y rezar. Si lo hacemos, no seremos capaces de entender cómo está funcionando y si está haciendo lo que creemos que debería. Por lo tanto, antes de empezar, deberíamos hacernos preguntas como «Para mi aplicación, ¿qué es lo bueno? ¿Cuáles son mis SLA y KPI? ¿Qué métricas se necesitan para depurar eficazmente un problema de rendimiento?»
Si tu aplicación tiene un rendimiento lento, o diferente al esperado, necesitarás datos para entender el motivo y poder mejorarla. Todas las aplicaciones de producción que se precien utilizan alguna forma de observabilidad y/o solución de monitorización. Estas herramientas, a menudo llamadas APM, le permiten ver las métricas de rendimiento críticas de Node.js sobre su aplicación en ejecución.
Ponerse en marcha con un APM
Los APMs vienen en diferentes formas y tamaños, todos con diferentes características, etiquetas de precio, implicaciones de seguridad, rendimiento, lo que sea. Vale la pena comparar un poco para encontrar la mejor herramienta para sus necesidades. Son estas herramientas las que nos van a dar la información y los datos que necesitamos cuando ejecutamos nuestras pruebas de rendimiento de Node.js.
Así que, si sabemos que debemos monitorizar nuestra aplicación, ¿qué deberíamos monitorizar exactamente?
En realidad, quieres tantos datos como sea posible, pero por mucho que nos gusten los datos, tenemos que ser realistas sobre dónde empezar. El mejor lugar para empezar es con las siguientes tres áreas:
- Logs agregados-Los logs de las aplicaciones son emitidos implícitamente por algunas bibliotecas o explícitamente por un desarrollador para obtener una visión de una aplicación. La mayoría de las herramientas de registros agregados permiten buscar y visualizar fácilmente los datos registrados. En nuestro caso, podríamos registrar el rendimiento de cada una de nuestras APIs y representarlo en un gráfico.
- Información sobre la infraestructura-Su aplicación se ejecutará en una serie de hosts, por lo que probablemente querrá ver todos los datos. Si está ejecutando en la nube, la mayoría de los proveedores le dan estos datos (aunque en una forma cruda) fuera de la caja. Los datos que obtendrá de estas herramientas cubrirán cosas como el uso de la CPU y la memoria de su anfitrión, datos de conexión, etc.
- Monitorización de aplicaciones: este tipo de herramienta normalmente se sitúa dentro del código de su aplicación y puede extraer información sobre cómo se están realizando/llamando las funciones, qué errores lanzamos, etc.
Algunas herramientas de APM, como Retrace, tienen todas o la mayoría de estas tres características integradas en una, mientras que otras pueden ser más especializadas. Dependiendo de tus necesidades, puede que quieras una herramienta que lo haga todo o toda una gama de herramientas para diferentes propósitos.
Herramientas adaptadas a Node.js
Además de las herramientas, también podemos incluir otras herramientas y perfiladores específicos de Node.js, como los gráficos de llama, que miran nuestra ejecución de funciones o extraen datos sobre nuestra ejecución de bucles de eventos. A medida que te vayas familiarizando con las pruebas de rendimiento de Node.js, tus necesidades de datos no harán más que crecer. Querrás seguir comprando, experimentando y actualizando tus herramientas para entender realmente tu aplicación.
Ahora que hemos configurado nuestras herramientas, tenemos perfiles realistas para nuestro rendimiento y entendemos el rendimiento de nuestra aplicación, estamos casi listos para ejecutar nuestras pruebas. Pero antes de hacerlo, hay un paso más: crear la infraestructura de pruebas.
Paso 4: Crear la infraestructura de pruebas de rendimiento de Node.js
Si lo deseas, puedes ejecutar las pruebas de rendimiento desde tu propia máquina, pero hay problemas para hacerlo. Hasta ahora, hemos tratado muy duro-con nuestros perfiles de prueba, por ejemplo-para asegurar que nuestras pruebas de rendimiento se replican. Otro factor en la replicación de nuestras pruebas es asegurar que siempre las ejecutamos en la misma infraestructura (léase: máquina).
Una de las maneras más fáciles de lograr una infraestructura de pruebas consistente es aprovechar el alojamiento en la nube. Elija un host/máquina desde la que desee lanzar sus pruebas y asegúrese de que cada vez que ejecute sus pruebas sea siempre desde la misma máquina -y preferiblemente desde la misma ubicación, también- para evitar sesgar sus datos en función de la latencia de las solicitudes.
Es una buena idea guionizar esta infraestructura, para poder crearla y desmontarla como y cuando sea necesario. A esta idea la llaman «infraestructura como código». La mayoría de los proveedores de la nube lo soportan de forma nativa, o puedes utilizar una herramienta como Terraform para ayudarte.
¡Phew! Hemos cubierto un montón de terreno hasta ahora, y estamos en el paso final: la ejecución de nuestras pruebas.
Paso 5: Ejecutar sus pruebas!
El último paso es realmente ejecutar nuestras pruebas. Si iniciamos nuestra configuración de línea de comandos (como hicimos en el paso 1), veremos las peticiones a nuestra aplicación Node.js. Con nuestra solución de monitorización, podemos comprobar cómo está funcionando nuestro bucle de eventos, si ciertas peticiones están tardando más que otras, si las conexiones se están agotando, etc.
La guinda del pastel para tus pruebas de rendimiento es considerar ponerlas en tu pipeline de construcción y pruebas. Una forma de hacerlo es ejecutar las pruebas de rendimiento durante la noche para poder revisarlas cada mañana. Artillery proporciona una forma agradable y sencilla de crear estos informes, que pueden ayudarte a detectar cualquier regresión en el rendimiento de Node.js.
Ahora tienes Node.js
Eso es todo.
Hoy, hemos cubierto la relevancia del bucle de eventos para el rendimiento de tu aplicación JavaScript, cómo elegir tus herramientas de pruebas de rendimiento, cómo configurar perfiles de pruebas de rendimiento consistentes con Artillery, qué monitorización querrás configurar para diagnosticar problemas de rendimiento de Node.js, y, por último, cómo y cuándo ejecutar sus pruebas de rendimiento para obtener el máximo valor para usted y su equipo.
Experimente con herramientas de monitoreo, como Retrace APM para Node.js, haga pequeños cambios para que pueda probar el impacto de los cambios, y revise sus informes de prueba con frecuencia para que pueda detectar regresiones. Ahora tienes todo lo que necesitas para aprovechar las capacidades de rendimiento de Node.js y escribir una aplicación súper performante que tus usuarios adoren!