6 truques de performance em Node.js

Atualizado em 10/06/2020!

Nos últimos anos JavaScript deixou de ser uma linguagem satélite para se tornar o core de muitos projetos de tecnologia. Cada vez mais desenvolvedores têm adotado esta tecnologia não apenas para o front mas para o backend, fazendo-a se tornar a linguagem mais popular do mundo segundo o StackOverflow ou a #7 segundo o Tiobe (ao que parece a galera de JS usa muito o StackOverflow, hehe).

JavaScript é uma linguagem simples de aprender o básico (Stanford que o diga!) e em conjunto com Node.js lhe permite construir todo o tipo de aplicação.

No entanto, dominar JavaScript e Node.js não é tão simples assim e, no artigo de hoje, quero trazer 6 truques/dicas/segredos de performance para você aplicar em seus projetos Node.js.

Atenção: talvez você conheça algumas dessas dicas de outros sites e livros. Não fui eu quem inventei todas elas, aprendi muitas pesquisando e estudando em outras fontes. Meu intuito aqui é agregar as melhores em um só artigo.

#1 – Faça caching

O uso de uma camada de cache na sua aplicação ajuda e muito a ganhar velocidade no acesso a dados recorrentes que os usuários solicitam e/ou que a aplicação precisa e uma das formas mais usadas de mecanismo de caching com Node.js é o Redis.

Redis é um mecanismo de armazenamento em memória que pode ser usado como base de dados, cache e message broker. Ele suporta estruturas de dados como strings, hashes, listas, conjuntos, conjuntos ordenados, bitmaps, logs, índices geoespaciais e streams de dados. Em outra oportunidade, quero trazer um tutorial de Redis para vocês.

Por enquanto, compare o código abaixo sem usar Redis. É um cliente que consome a API de livros do Google, sempre indo na mesma pegar os livros:

A performance desse código não é ruim, leva pouco menos de 1s para ir no Google pegar esta informação:

Sem Redis
Sem Redis

Agora, o mesmo código mas usando Redis, criando uma camada de cache intermediária:

A diferença entre um e outro é que, no segundo código, eu sempre verifico se eu já não tenho o título no cache, baseado no ISBN. Se eu tiver, retorno o que está no cache, caso contrário, vou no Google pesquisar e, além de retornar, salvo no cache para consultas mais rápidas posteriormente.

O resultado, quando o dado já está em cache, é assustadoramente mais rápido, menos de 1ms. Sim, menos de um milissegundo!!!

Com Redis
Com Redis

Livro Node.js com MySQL

#2 – Tenha índices

Todo mundo que já trabalhou com banco de dados já deve ter ouvido falar de índices alguma vez na sua vida. Nem que seja o mais básico de todos que é o índice primário/chave primária. No entanto, geralmente ele não é o bastante em aplicações do mundo real.

Vamos pegar o MongoDB como exemplo, um banco de dados NoSQL muito utilizado em conjunto do Node.js. Antes de falar de índices pra ele, vamos descobrir como entender se a sua coleção precisa de um novo índice. Para analisar a performance de uma consulta em MongoDB, usamos a função explain, como abaixo:

A consulta será executada e como retorno teremos os dados de seu planejamento e da sua execução.

Do trecho acima, tem dois pontos importantes a serem analisados:

  • nReturned: número de documentos retornados, neste caso, apenas 1;
  • totalDocsExamined: número total de documentos scaneados para encontrar o que queríamos, neste caso 1039;

Entendeu o drama? O MongoDB teve de olhar, um a um, 1039 documentos até encontrar o que queríamos!

Aqui um código rápido de criação de índice no campo email da coleção users:

E o resultado da mesma consulta, 1 documento consultado e 1 retornado:

Em relação ao tempo de execução, ambas foram instantâneas (executionTimeMillis: 0), mas porque tem poucos dados na base. Em volumes gigantes (big data), a diferença de tempo será gritante também.

Eu falo em mais detalhes de MongoDB em meu livro.

#3 – Tenha logs

Uma das coisas que mais afeta as aplicações em produção são os erros. Não apenas porque eles estragam a experiência dos usuários, mas porque eles degradam a performance da aplicação em si, pois erros derrubam threads, geram efeitos colaterais e muitas vezes são invisíveis.

Para que saiam dessa situação de invisibilidade, precisamos expô-los com logs. E não falo de console.log, mas de uso de pacotes de logging mais profissionais como Winston, Morgan e Bunyan.

Abaixo, um exemplo básico de uso do Winston:

#4 – Implemente HTTP/2

HTTP/2 comumente chamado de SPDY é o protocolo padrão para a web mais recente, desenvolvido pelo grupo de trabalho HTTP da IETF. HTTP/2 torna a navegação web mais rápida, fácil e usando menos banda. Ele foca em performance, especialmente para resolver problemas que ainda ocorrem na versão mais usada do HTTP, a 1.x.

Atualmente, grandes nomes com Google, Facebook e Youtube já implementam este protocolo em suas páginas e estão encorajando a cada vez mais desenvolvedores usarem o mesmo. Ele é um pouco mais complexo que o normal, pois, por exemplo, exige conexão criptografada (SSL).

Abaixo, um exemplo de server HTTP/2 em Node.js, do site oficial:

Para gerar os certificados (arquivos PEM) que ele precisa no código, você pode usar o OpenSSL via linha de comando:

Ou gerar no seu servidor usando Lets Encrypt, como comento neste post.

#5 – Use um cluster

Por padrão, Node.js roda em uma thread única e consequentemente em um único core do processador, o tornando ineficiente se estiver em uma máquina com múltiplos cores.

Mas já tem muito tempo que isso foi resolvido através da implementação de clusterização de thread em Node.js, o que permite criar processos filhos que compartilham a porta do servidor, permitindo que o Node possa aguentar um grande volume de requests em servidores com vários cores.

O jeito mais fácil de clusterizar a sua aplicação Node.js é usando o PM2. Já falei do PM2 em mais de uma oportunidade aqui no blog e até gravei um vídeo falando sobre ele. Basicamente ele é um gerenciador de processos que pode ser usado com Node.js para garantir que ele vai estar sempre rodando no servidor.

Quando usamos PM2, podemos subir um cluster de processos iguais sem fazer qualquer modificação no seu código, apenas passando um parâmetro na hora de inicializar o seu processo com este utilitário:

Assim, o PM2 automaticamente já vai escalar a sua aplicação para TODOS os cores da máquina em que ele estiver rodando.

PM2 Cluster
PM2 Cluster

#6 – Monitore a sua aplicação

A última dica é uma das mais importantes: monitore a sua aplicação!

E quando falo em monitoria não é apenas ficar olhando uso de memória e CPU no servidor, mas sim usar alguma solução profissional de monitoria como New Relic, Dynatrace, Stackify, Ruxit, LogicMonitor e Monitis.

Somente com uma ferramenta de monitoria em tempo real você poderá garantir que a sua aplicação está tendo uma boa performance e seus usuários estão sendo bem atendidos do ponto de vista sistêmico, ao menos.

Outra dica legal ainda dentro do âmbito de monitoração é fazer periodicamente testes de stress com a sua aplicação. Para isso eu recomendo usar o Artillery, como mostro no vídeo abaixo.

Até a próxima!

Gostou do artigo? Conheça meu curso online de Node.js e MongoDB clicando no banner abaixo!

Curso Node.js e MongoDB