We know Node.js for its lightning-fast performance. No entanto, como em qualquer linguagem, você pode escrever código Node.js que tem um desempenho pior para seus usuários do que você gostaria. Para combater isso, nós precisamos de testes de performance adequados. Hoje, vamos cobrir exatamente isso com um olhar profundo sobre como configurar e executar um teste de performance e analisar os resultados para que você possa fazer aplicações Node.js lightning-fast.
A melhor maneira de entender como testar a performance da sua aplicação é caminhar por um exemplo.
Você pode usar Node.js para muitos propósitos: escrever scripts para executar tarefas, executar um servidor web, ou servir arquivos estáticos, como um website. Hoje, vamos caminhar pelos passos para testar uma web API HTTP do Node.js. Mas se você está construindo algo mais no Node, não se preocupe – muitos dos princípios serão similares.
- A natureza única da performance do Node.js
- O loop do evento
- Desempenho do Node.js e o loop do evento
- Passo 1: Escolhendo a ferramenta de teste de desempenho do Node.js
- Passo 2: Crie um perfil de teste de desempenho do Node.js
- Alavancando múltiplos perfis de teste
- Replicar sistemas distribuídos em larga escala
- Passo 3: Configure sua observabilidade/monitoramento
- Começando a funcionar com um APM
- Ferramentas sob medida para Node.js
- Passo 4: Criar infra-estrutura de testes de performance do Node.js
- Passo 5: Execute seus testes!
- Agora você tem Node.js
A natureza única da performance do Node.js
Antes de começarmos, vamos dar uma olhada rápida em uma das características mais únicas da performance do Node.js. Precisaremos ter conhecimento dessas características mais tarde quando executarmos nossos testes de desempenho.
De que estou falando?
A grande consideração para as aplicações Node.js é o seu comportamento de execução para conclusão – facilitado pelo que é conhecido como o loop do evento. Agora, eu sei o que você está pensando: isso é muito. Então vamos quebrar isso um pouco para que entendamos o que isso significa.
Comecemos com um único threading. Threading, como um conceito, permite o processamento simultâneo dentro de uma aplicação. O Node.js não tem essa capacidade, pelo menos não no sentido tradicional. Em vez disso, para escrever aplicações que realizam múltiplas tarefas ao mesmo tempo, temos o código assíncrono e o loop do evento.
O loop do evento
Qual é o loop do evento?
O loop do evento é a forma do Node.js de quebrar processos de longa duração em pequenos pedaços. Ele funciona como um batimento cardíaco: A cada poucos milisegundos, o Node.js verifica uma fila de trabalho para iniciar novas tarefas. Se houver trabalho, ele os trará para a pilha de chamadas e então os executará até a conclusão (falaremos sobre run-to-completion em breve).
Ao quebrar tarefas, Node.js pode multi-tarefas, que é seu substituto para threading. Isso significa que enquanto uma tarefa está esperando, outra pode começar. Então, ao invés de threading, usamos código async, facilitado por estilos de programação como callbacks, promessas, e async/await. A maioria das APIs de nós out-of-the-box tem tanto um método de execução síncrono e assíncrono.
Okay, então talvez você esteja se perguntando: o que todo esse jargão tecno tem a ver com performance?
Deixe-me explicar…
Desempenho do Node.js e o loop do evento
Imagine que você está construindo uma aplicação Node.js com dois pontos finais: um para o upload de arquivos e outro que vai buscar um perfil de usuário. A API de perfil de usuário provavelmente será requisitada significativamente mais vezes do que o upload do arquivo, e se não responder rápido o suficiente, irá bloquear cada carregamento de página para cada usuário – não é bom.
A API de upload de usuário é usada com pouca frequência. Além disso, os usuários esperam que o upload de tarefas leve tempo, mas eles são muito menos indulgentes com os tempos de carregamento de páginas. Se não programarmos com o loop do evento em mente, enquanto o arquivo está sendo carregado, o Node.js pode acabar monopolizando todos os recursos do sistema e pode bloquear outros usuários de usar sua aplicação-uh-oh!
E é por isso que você precisa entender a natureza do Node.js com um único threaded. À medida que mudamos nossa aplicação, precisamos considerar este comportamento. Queremos evitar fazer tarefas de longa duração de forma síncrona, tais como fazer solicitações de rede, escrever arquivos ou executar um cálculo pesado.
Agora sabemos sobre a natureza single-threaded do Node.js, podemos usá-lo em nosso benefício. Vamos passo a passo como você pode configurar, executar e analisar um teste de desempenho da sua aplicação Node.js para ter certeza que você está fazendo o seu melhor para aproveitar as capacidades de desempenho do Node.js.
Passo 1: Escolhendo a ferramenta de teste de desempenho do Node.js
Primeiro, você vai querer escolher uma ferramenta que vai permitir que você execute seus testes de desempenho. Existem muitas ferramentas lá fora, todas com diferentes prós e contras para o ajuste de desempenho do Node.js. Uma coisa principal a considerar é que mesmo que você esteja testando uma aplicação Node.js se você estiver indo para um teste de performance do mundo externo através de uma rede, não importa se a sua ferramenta de teste de performance está escrita em Node.js.
Para testes de performance HTTP básicos, eu gosto de Artillery uma ferramenta de teste de performance direta escrita em Node.js. Também é particularmente bom em executar testes de performance para solicitações de API. Artillery funciona escrevendo um arquivo de configuração que define seu perfil de carga. Você diz ao Artillery quais pontos finais você quer requisitar, a que taxa, por que duração, etc.
Um script de teste básico se parece com isto:
config: target: 'https://artillery.io' phases: - duration: 60 arrivalRate: 20 defaults: headers: x-my-service-auth: '987401838271002188298567'scenarios:- flow:- get:url: "/docs"
Aqui, você está requisitando o site do Artillery por 60 segundos de duração com 20 novos usuários chegando na URL.
Então, para executar o teste, você simplesmente executa:
artillery run your_config.yml
Artilharia fará tantos pedidos à sua aplicação quantos você instruiu. Isto é útil para construir perfis de teste de desempenho que imitam o seu ambiente de produção. O que eu quero dizer com perfil de teste de performance? Vamos cobrir isso agora.
Passo 2: Crie um perfil de teste de desempenho do Node.js
Um perfil de teste de desempenho, como acima, é uma definição de como seu teste de desempenho irá funcionar. Você vai querer imitar como o seu tráfego de produção faz ou é esperado, comportar-se, se possível, para fazer um ajuste preciso do desempenho do Node.js. Por exemplo, se você está construindo um site de eventos, você esperaria muito tráfego na hora de lançar os ingressos, então você gostaria de construir um perfil que imita esse comportamento. Você gostaria de testar a capacidade da sua aplicação de escalar com grandes quantidades de uma carga em um curto espaço de tempo. Alternativamente, se você estiver rodando um site de comércio eletrônico, você pode esperar até mesmo tráfego. Aqui, seus perfis de teste de desempenho devem refletir esse comportamento.
Alavancando múltiplos perfis de teste
Um ponto divertido e interessante a se notar é que você pode criar diferentes perfis de teste e executá-los de uma forma sobreposta. Por exemplo, você pode criar um perfil que imita o seu nível base de tráfego – digamos, 100 pedidos por minuto – e depois imitar o que poderia acontecer se você visse muito tráfego para o seu site, digamos, se você colocasse alguns anúncios nos motores de busca. Testar múltiplos cenários é importante para o ajuste completo do desempenho do Node.js.
Replicar sistemas distribuídos em larga escala
Preciso de um segundo aqui para notar algo: Quando uma aplicação atinge um certo tamanho, imitar a carga desta forma perde a viabilidade. Os volumes de tráfego que você pode ter podem ser tão selvagens, imprevisíveis ou grandes em volume que é difícil criar uma forma realista de testar sua aplicação antes do lançamento.
Mas e se este for o caso? O que nós fazemos? Nós testamos em produção.
Você pode pensar, “Woah, espere! Não deveríamos testar antes do lançamento?”
Você pode, mas quando um sistema atinge um certo tamanho, pode fazer sentido alavancar diferentes estratégias de teste de desempenho. Você pode aproveitar conceitos como o lançamento de canários para colocar suas mudanças em produção e testá-las apenas com uma certa porcentagem de usuários. Se você vir uma queda de performance, você pode trocar esse tráfego de volta para sua implementação anterior. Este processo realmente encoraja a experimentação, e a melhor parte é que você está testando em sua aplicação de produção real, então não se preocupe com resultados de testes que não imitem a produção.
Até agora nós decidimos sobre nossas ferramentas, e criamos perfis que recriam nossa produção, como tráfego e cargas de trabalho. O que vamos fazer a seguir? Precisamos garantir que temos os dados necessários para analisar nossa aplicação, e fazemos isso através das ferramentas de monitoramento de desempenho Node.js e Application Performance Management (APM). O que é um APM? Continue lendo, e eu aviso-o!
Passo 3: Configure sua observabilidade/monitoramento
Não queremos apenas executar nosso teste de desempenho contra nossa aplicação e esperar e rezar. Se o fizermos, não conseguiremos entender como está a funcionar e se está a fazer o que achamos que deveria. Portanto, antes de começarmos, devemos nos fazer perguntas como “Para a minha aplicação, como é que é bom? Quais são os meus SLAs e KPIs? Que métricas são necessárias para efetivamente depurar um problema de desempenho?”
Se a sua aplicação funciona lentamente, ou diferente do que você esperava, você precisará de dados para entender o porquê para que você possa melhorá-la. Todas as aplicações de produção que valem o seu sal estão usando alguma forma de observabilidade e/ou solução de monitoramento. Estas ferramentas, muitas vezes chamadas de APMs, permitem que você visualize métricas críticas de desempenho do Node.js sobre sua aplicação em execução.
Começando a funcionar com um APM
APMs vêm em diferentes formas e tamanhos, todos com diferentes características, etiquetas de preço, implicações de segurança, desempenho, o que você quiser. Vale a pena comprar um pouco para encontrar a melhor ferramenta para as suas necessidades. São estas ferramentas que nos vão dar os insights e dados que precisamos quando rodamos nossos testes de desempenho do Node.js.
Então, se sabemos que devemos monitorar nossa aplicação – o que exatamente devemos monitorar?
Idealmente, você quer o máximo de dados possível – mas tanto quanto amamos os dados; temos que ser realistas sobre por onde começar! O melhor lugar para começar é com as seguintes três áreas:
- Logs agregados – os logs da aplicação emitem implicitamente por algumas bibliotecas ou explicitamente por um desenvolvedor para obter uma visão sobre uma aplicação. A maioria das ferramentas de log agregado permite que você facilmente pesquise e visualize seus dados registrados. Em nosso caso, nós poderíamos logar o desempenho de cada uma de nossas APIs e plotá-las em um gráfico.
- Informações da infraestrutura – Sua aplicação será executada em uma série de tipos, então você provavelmente vai querer ver todos os dados. Se você estiver rodando na nuvem, a maioria dos provedores lhe fornece esses dados (embora de forma bruta) fora da caixa. Os dados que você obterá dessas ferramentas cobrirão coisas como CPU e uso de memória do seu host, dados de conexão, etc.
- Monitoramento de aplicações – Esse tipo de ferramenta normalmente fica dentro do código da sua aplicação e pode extrair insights sobre como as funções estão executando/sendo chamadas, quais erros nós lançamos, etc.
Algumas ferramentas APM, como o Retrace, têm todas ou a maioria dessas três características enroladas em uma, enquanto outras podem ser mais especializadas. Dependendo dos seus requisitos, você pode querer uma ferramenta que faça tudo ou toda uma gama de ferramentas para diferentes propósitos.
Ferramentas sob medida para Node.js
No topo das ferramentas, também podemos incluir outras ferramentas e profilers específicos para Node.js, como gráficos de chama, que olham para a nossa execução de funções ou extraem dados sobre a nossa execução de loop de eventos. À medida que você se familiariza mais com os testes de desempenho do Node.js, seus requisitos de dados só vão crescer. Você vai querer continuar comprando, experimentando e atualizando suas ferramentas para realmente entender sua aplicação.
Agora nós configuramos nossas ferramentas, temos perfis realistas para nosso desempenho, e entendemos nosso desempenho de aplicação, estamos quase prontos para executar nossos testes. Mas antes de fazermos isso, há mais um passo: criar infra-estrutura de testes.
Passo 4: Criar infra-estrutura de testes de performance do Node.js
Você pode executar testes de performance a partir de sua própria máquina se desejar, mas há problemas em fazer isso. Até agora, nós tentamos muito – com nossos perfis de teste, por exemplo – garantir que nossos testes de desempenho se reproduzam. Outro fator para replicar nossos testes é garantir que sempre os executamos na mesma infra-estrutura (leia-se: máquina).
Uma das maneiras mais fáceis de conseguir uma infra-estrutura de testes consistente é alavancar o cloud hosting. Escolha um host/máquina a partir da qual você quer lançar seus testes e certifique-se de que cada vez que você executar seus testes é sempre da mesma máquina – e de preferência do mesmo local, também – para evitar distorcer seus dados com base na latência dos pedidos.
É uma boa idéia scriptar essa infra-estrutura, para que você possa criá-la e desmontá-la como e quando necessário. Eles chamam esta ideia de “infra-estrutura como código”. A maioria dos provedores de nuvens suporta nativamente, ou você pode usar uma ferramenta como a Terraform para ajudá-lo.
Phew! Nós cobrimos muito terreno até agora, e estamos na etapa final: rodando nossos testes.
Passo 5: Execute seus testes!
O último passo é realmente executar nossos testes. Se iniciarmos nossa configuração de linha de comando (como fizemos no passo 1), veremos pedidos para a nossa aplicação Node.js. Com nossa solução de monitoramento, podemos verificar para ver como nosso loop de eventos está se desempenhando, se certos pedidos estão demorando mais do que outros, se as conexões estão demorando mais, etc.
A cereja no bolo para seus testes de desempenho é considerar colocá-los em seu pipeline de construção e teste. Uma maneira de fazer isso é fazer seus testes de desempenho durante a noite para que você possa revisá-los todas as manhãs. Artilharia fornece uma maneira simples e agradável de criar esses relatórios, que pode ajudá-lo a detectar qualquer regressão de desempenho do Node.js.
Agora você tem Node.js
Isso é um embrulho.
Hoje, nós cobrimos a relevância do loop do evento para o desempenho da sua aplicação JavaScript, como escolher a sua ferramenta de teste de desempenho, como configurar perfis consistentes de teste de desempenho com Artilharia, que monitoramento você vai querer configurar para diagnosticar o Nodo.js problemas de desempenho e, finalmente, como e quando executar seus testes de desempenho para obter o máximo valor para você e sua equipe.
Experimente com ferramentas de monitoramento, como Retrace APM for Node.js, faça pequenas alterações para que você possa testar o impacto das alterações e revise seus relatórios de teste com freqüência para que você possa detectar regressões. Agora você tem tudo o que precisa para aproveitar as capacidades de desempenho do Node.js e escrever um aplicativo super performante que seus usuários adoram!