Medindo o Uso de CPU em Aplicações Node.js com a API Inspector

RESUMO

O artigo explora como usar a API Inspector do Node.js para identificar e otimizar gargalos de CPU, essencial para melhorar a performance em produção. Com exemplos práticos, mostra como capturar e analisar dados de uso de CPU no Chrome DevTools, identificando funções críticas e aplicando otimizações que reduziram significativamente o tempo de execução.

1. Resultado

A API Inspector do Node é uma solução nativa para medir o uso de CPU, permitindo realizar profiling de CPU e capturar dados detalhados de execução que ajudam a identificar onde os recursos estão sendo mais demandados, sem a necessidade de instalar e configurar ferramentas. Neste artigo, vamos explorar como configurar e utilizar a API Inspector para capturar e interpretar dados de CPU em sua aplicação Node.js, permitindo que você descubra gargalos nas suas aplicações Node.

2. Situação

Em ambientes de produção, gargalos de CPU podem impactar negativamente a experiência do usuário e o consumo de recursos, tornando essencial o monitoramento do uso de CPU. Mas como entender quais partes do código estão consumindo mais CPU em uma aplicação Node?

3. Impacto

  • Identificação de funções críticas com alto uso de CPU.
  • Possibilidade de otimização do código para reduzir tempos de resposta.
  • Melhoria significativa na experiência do usuário e eficiência operacional.

4. Resolução

A API Inspector é uma interface nativa no Node que permite acessar o protocolo de inspeção V8, o mesmo utilizado pelo Chrome DevTools e para debugar aplicações Node. Esse protocolo oferece uma série de métodos para inspecionar e analisar o desempenho de aplicações Node, incluindo o profiling de CPU, de heap, ou debug. Com essa API, é possível capturar dados detalhados sobre a execução do código ou armazená-los para análise posterior.

A API Inspector funciona criando uma Session, através da qual podemos iniciar o profiling, controlando o acesso aos dados do tempo de execução da aplicação. Esse método permite identificar gargalos e otimizar o uso de CPU em trechos específicos do código, monitorando o custo computacional de funções.

4.1. Exemplo prático

Para esse exemplo você precisa ter configurado o Node e o Google Chrome (iremos usá-lo para visualizar os dados). 

Vamos começar com uma API simples em express com duas funções que são acessadas através da rota “/crypto”, as funções “delay” e “encrypt” são funções que utilizam a CPU massivamente, porém de formas diferentes. A função “delay” testa números até 10 milhões e separa os números primos, já a função “encrypt” gera uma chave hash através de 1 milhão de iterações. Provavelmente você já percebeu um problema grave nessa aplicação, não se preocupe iremos resolvê-lo no final desse artigo, por enquanto vamos concentrar nosso foco em capturar dados de uso de CPU.

Você também pode acessar o projeto completo no repositório.

4.2. Configurando e Utilizando a API Inspector para Medir o Uso de CPU

Primeiro vamos iniciar uma sessão com o Node Inspector

const { Session } = require('node:inspector/promises');

Agora podemos interagir com a API do V8 Inspector através do comando:

await session.post(v8_method)

A lista completa dos métodos pode ser acessada aqui.

Vamos ativar e iniciar o profiling da aplicação com esses comandos

await session.post('Profiler.enable');
await session.post('Profiler.start');


Executamos o código que desejamos monitorar e por fim finalizamos o profiling e salvamos o resultado em um arquivo assim:

const { profile } = await session.post('Profiler.stop');
fs.writeFileSync('./profileSync.cpuprofile', JSON.stringify(profile));

4.3. Interpretando os resultados de CPU com o DevTools do Chrome

Vamos iniciar a aplicação e executar uma requisição para a rota /crypto, você vai notar que a requisição leva um tempo considerável, em média 5 segundos. Após a execução o arquivo “profileSync.cpuprofile” será criado na raiz do projeto, abra o Google Chrome e abra o DevTools (uma das formas é clicar com o botão direito em Inspecionar), na aba Performance basta arrastar o arquivo gerado para dentro dela.

Imagem 1 – Visualização do CPU profiler via Chrome DevTools

Na visão “Call tree” (porção inferior) podemos ver o tempo e uso do CPU de cada uma das funções. Ambas estão críticas:

encrypt: 2,5 segundos (53,2%)
delay: 2,2 segundos (46,7%)

Agora que medimos descobrimos onde é o gargalo da nossa aplicação, o trabalho de melhoria de performance não para aqui, agora precisamos analisar as duas funções e descobrir se há espaço para otimiza-las, se houver fazemos e medimos novamente para validar se a otimização de fato funcionou.

4.4. Resolvendo o problema e interpretando os novos resultados

O objetivo deste artigo é mostrar como medir o uso de CPU em aplicações Node, por isso não entrarei em detalhes sobre a otimização aplicada, porém no arquivo index_async.js as otimizações foram implementadas. Execute os testes com esse arquivo, ele irá gerar um novo arquivo de profiling que iremos examinar.

Imagem 2 – Visualização do CPU profiler via Chrome DevTools após correção

Após a correção o tempo total de execução caiu para quase a metade e ambas as funções foram executadas. O tempo de idle corresponde ao tempo de espera para terminar a requisição, isso significa que houve um tempo de espera (idle) de 117 ms.

Podemos fazer pequenos ajustes no código para executar apenas a função encrypt e teremos um arquivo de profiling semelhante a esse:

Imagem 3 – Visualização do CPU profiler via Chrome DevTools apenas para a função encrypt

Todo tempo de execução da aplicação foi computado como idle, isto significa que a função encrypt levou todo esse tempo para executar, a razão pela qual vemos como idle é porque o V8 Inspector captura apenas o processo executado na main thread por isso vemos que a main thread esperou o tempo total em idle até a função encrypt ser resolvida.

5. Conclusão

Medir e entender o uso de CPU é essencial para otimizar o desempenho de aplicações Node.js, especialmente em cenários de produção onde a eficiência de recursos é fundamental. Neste artigo, vimos como utilizar a API Inspector do Node para realizar o profiling de CPU e capturar dados detalhados sobre o consumo de recursos em tempo de execução. Analisar esses dados permite identificar funções e operações que demandam alto uso de CPU, possibilitando otimizações focadas e melhorias de desempenho.

Existem outras ferramentas e abordagens para analisar com mais detalhes aplicações Node, como por exemplo instrumentar a aplicação com dados de Log, Tracing e Metrics, possibilitando a coleta de dados em tempo real. Porém esse é um assunto para um próximo artigo.

Quer continuar aprimorando suas habilidades em Node? Siga o blog da EximiaCo para mais conteúdos sobre melhores práticas em desenvolvimento Node.

AUTORIA

Leandro Simões

Engenheiro de Software

Gostaria de mais informações?

Se você tem interesse neste assunto ou gostaria de mais informações sobre como a EximiaCo pode ajudar a sua empresa a utilizar a tecnologia para gerar mais resultados, entre em contato conosco.

Área de colaboradores

Esse ambiente é de acesso restrito à equipe de colaboradores da EximiaCo.

Trabalha na EximiaCo? Então conecte-se com sua conta:

Tenho interesse em conversar

Se você está querendo gerar mais resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você: