DEV Community

Cover image for Como identificar gargalos de memória em uma aplicação nodejs 🤩
Siqueira
Siqueira

Posted on • Updated on

Como identificar gargalos de memória em uma aplicação nodejs 🤩

Hoje normalmente não nos preocupamos com consumo recursos ao desenvolver uma nova aplicação, porém quando temos como pauta a performance da aplicação as coisas se complicam.

O problema:

Quando temos uma aplicação que não consegue lidar com consumo de memória, temos um problema.

Pois quando ela não auto gerencia os recursos disponíveis, ela corre grande risco de ficar indisponível, e até perder dados.

Um exemplo é uma aplicação que consome mensagens de alguma fila, se ela não controla a quantidade de mensagens a ser processada de acordo com os recursos disponíveis, ela pode acabar ultrapassado o limite de consumo e ser encerrada.

A Busca pela solução:

Quando isso ocorre temos alguns problemas que podem ser elencados, sua aplicação pode estar com Memory Leaks, ou estar consumindo mais RAM do que o disponível.

Tendo essas possibilidades em vista temos que investigar a execução da aplicação para coletar mais dados.

O primeiro passo é montar seu ambiente local para reproduzir o cenário, porém antes de seguir com a reprodução devemos configurar um pacote que nos ajudará a coletar métricas da nossa aplicação o heapdump.

A instalação e configuração é bem simples conforme abaixo:

Rode a aplicação utilizando o seguinte comando:

env NODE_HEAPDUMP_OPTIONS=nosignal node app.js
Enter fullscreen mode Exit fullscreen mode

Após a configuração chegou a hora de encontrar o problema, ao rodar a aplicação temos como objetivo leva-la ao limite, após estourar o uso dos recursos e encerrar, a aplicação terá gerado um relatório de uso de recursos, você encontrará na pasta raiz.

Para que possamos identificar exatamente onde ocorre o problema também colete dados da aplicação no ponto de execução você acredita não ter gargalos.

E com isso podemos usar o chrome dev tools para visualizar o relatório conforme abaixo:

Após a importação temos acesso as métricas de consumo de memória da aplicação, devemos ficar atentos a alguns indicadores.

A linha do tempo, com ele você pode diagnosticar o uso excessivo de memória, para identificar os pontos do gargalo:

O gráfico que você vê exibirá a memória alocada para seu aplicativo. Se acontecer de estar consumindo uma quantidade cada vez maior disso ao longo do tempo (sem nunca cair), é uma indicação de que você pode ter um vazamento de memória(Memory Leak).

O perfil de um aplicativo saudável deve se parecer mais com uma curva dente de serra, pois a memória é alocada e depois liberada quando o coletor de lixo entra.

Depois de suspeitar que há um vazamento de memória, o profiler Heap pode ser usado para descobrir a origem do vazamento.

Encontrar problemas de memória mesmo com as métricas é complicado mas para começar é a visualização Resumo do perfilador de heap. Você pode então comparar os heaps snapshots coletados para confirmar quais alocações foram feitas junto com seu impacto na memória.

Em cada snapshot temos o consumo total de memória:

Após selecionar o snapshot desejado podemos ver todos tipos de variáveis e suas quantidades criadas durante a execução do app.

Devemos ficar atentos a dois indicadores Shallow Size, que representa o tamanho do objeto alocado em bytes.

E additional retained size que é o tamanho retido dos objetos, ou seja parte dos objetos que não é limpa com garbage collector.

Bom agora que estamos cientes do indicadores e temos dois relatórios em mãos temos como proximo passo comparar os dois.

Ao comparar temos como identificar partes do código que utilizar uma quantidade de memória maior. A investigação nem sempre é assertiva, porém ela nos da uma noção de onde atacar.

A solução:

Com todos os dados em mãos devemos implementar uma solução vamos usar como exemplo uma aplicação que consome mensagens de uma fila irrestritamente conforme a imagem abaixo:

Ao identificar que o gargalo é no consumo uma saída é gerenciar o consumo de mensagens de acordo com memória atual usada, e fazer isso utilizando a função "memoryUsage" nativa do nodejs, essa função retorna o objeto abaixo:

{
  rss: 4935680,
  heapTotal: 1826816,
  heapUsed: 650472,
  external: 49879,
  arrayBuffers: 9386
}
Enter fullscreen mode Exit fullscreen mode

Para otimizar o uso de memória iremos consumir mensagens com base no indicador "heapUsed" que retorna a quantidade de memória alocada no momento. E também com base no total de memória disponível que pode ser obtido através da função "totalmem" presente dentro do modulo os, essa função retorna o total de memória em bytes disponível no ambiente.

No caso acima utilizamos a seguinte estratégia, antes de consumir uma mensagem verificamos o uso total de memória caso esteja dentro do limite seguro a aplicação segue com o processo, caso contrario ela espera o uso da memória diminuir para voltar a processar as mensagens.

Essa é uma das formas de controlar facilmente o uso de memória dentro de uma aplicação nodejs.

Espero que tenham gostado até a próxima!

Latest comments (0)