BLOG | NGINX

5 dicas de desempenho para aplicativos Node.js

NGINX-Parte-de-F5-horiz-preto-tipo-RGB
Miniatura de Floyd Smith
Floyd Smith
Publicado em 16 de novembro de 2015
Se #nginx não estiver na frente do seu servidor de nó, você provavelmente está fazendo errado.
Bryan Hughes no Twitter

Node.js é a ferramenta líder para criação de aplicativos de servidor em JavaScript, a linguagem de programação mais popular do mundo. Oferecendo a funcionalidade de um servidor web e de um servidor de aplicativos, o Node.js agora é considerado uma ferramenta essencial para todos os tipos de desenvolvimento e entrega baseados em microsserviços. (Baixe um relatório gratuito da Forrester sobre Node.js e NGINX .)

O Node.js pode substituir ou complementar o Java ou o .NET para desenvolvimento de aplicativos de backend.

O Node.js é de thread único e usa E/S não bloqueantes, o que lhe permite dimensionar e suportar dezenas de milhares de operações simultâneas. Ele compartilha essas características arquitetônicas com o NGINX e resolve o problema C10K – suportando mais de 10.000 conexões simultâneas – que o NGINX também foi inventado para resolver. O Node.js é conhecido pelo alto desempenho e produtividade do desenvolvedor.

Então, o que poderia dar errado?

O Node.js tem alguns pontos fracos e vulnerabilidades que podem tornar os sistemas baseados em Node.js propensos a baixo desempenho ou até mesmo travamentos. Os problemas surgem com mais frequência quando um aplicativo web baseado em Node.js passa por um rápido crescimento de tráfego.

Além disso, o Node.js é uma ótima ferramenta para criar e executar lógica de aplicativo que produz o conteúdo principal e variável para sua página da web. Mas não é tão bom para servir conteúdo estático – imagens e arquivos JavaScript, por exemplo – ou balanceamento de carga entre vários servidores.

Para aproveitar ao máximo o Node.js, você precisa armazenar em cache o conteúdo estático, fazer proxy e balancear a carga entre vários servidores de aplicativos e gerenciar a contenção de portas entre clientes, Node.js e auxiliares, como servidores que executam Socket.IO. O NGINX pode ser usado para todos esses propósitos, o que o torna uma ótima ferramenta para ajuste de desempenho do Node.js.

Use estas dicas para melhorar o desempenho do aplicativo Node.js:

  1. Implementar um servidor proxy reverso
  2. Armazenar em cache arquivos estáticos
  3. Balanceamento de carga de tráfego em vários servidores
  4. Conexões proxy WebSocket
  5. Implementar SSL/TLS e HTTP/2

Observação:  Uma solução rápida para o desempenho do aplicativo Node.js é modificar sua configuração do Node.js para aproveitar servidores modernos e multinúcleo. Confira a documentação do Node.js para saber como fazer com que o Node.js gere processos filho separados — igual ao número de CPUs no seu servidor web. Cada processo então, de forma quase mágica, encontra um lar em uma e somente uma das CPUs, proporcionando um grande aumento no desempenho.

Dica 1 – Implemente um servidor proxy reverso

Nós da NGINX, Inc. sempre ficamos um pouco horrorizados quando vemos servidores de aplicativos diretamente expostos ao tráfego de entrada da Internet, usados no núcleo de sites de alto desempenho. Isso inclui muitos sites baseados em WordPress , por exemplo, bem como sites Node.js.

O Node.js, mais do que a maioria dos servidores de aplicativos, foi projetado para escalabilidade, e seu lado de servidor web pode lidar razoavelmente bem com muito tráfego da Internet. Mas o serviço web não é a razão de ser do Node.js – não é para isso que ele foi realmente criado.

Se você tem um site de alto tráfego, o primeiro passo para aumentar o desempenho do aplicativo é colocar um servidor proxy reverso na frente do seu servidor Node.js. Isso protege o servidor Node.js da exposição direta ao tráfego da Internet e permite grande flexibilidade no uso de vários servidores de aplicativos, no balanceamento de carga entre os servidores e no armazenamento em cache de conteúdo.

Colocar o NGINX na frente de uma configuração de servidor existente como um servidor proxy reverso , seguido por usos adicionais, é um caso de uso central do NGINX, implementado por dezenas de milhões de sites em todo o mundo.

Há vantagens específicas em usar o NGINX como um servidor proxy reverso Node.js , incluindo:

  • Simplificando o tratamento de privilégios e atribuições de portas
  • Servindo imagens estáticas de forma mais eficiente (veja a próxima dica )
  • Gerenciando travamentos do Node.js com sucesso
  • Mitigando ataques DoS

Observação : Esses tutoriais explicam como usar o NGINX como um servidor proxy reverso em ambientes Ubuntu 14.04 ou CentOS e são uma visão geral útil para qualquer um que esteja colocando o NGINX na frente do Node.js.

Dica 2 – Armazene em cache arquivos estáticos

À medida que o uso de um site baseado em Node.js cresce, o servidor começa a apresentar problemas. Há duas coisas que você precisa fazer neste momento:

  1. Aproveite ao máximo o servidor Node.js
  2. Facilite a adição de servidores de aplicativos e o balanceamento de carga entre eles

Na verdade, isso é fácil de fazer. Comece implementando o NGINX como um servidor proxy reverso, conforme descrito na dica anterior . Isso facilita a implementação de cache, balanceamento de carga (quando você tem vários servidores Node.js) e muito mais.

O site do Modulus, uma plataforma de contêiner de aplicativos, tem um artigo útil sobre como turbinar o desempenho de aplicativos Node.js com NGINX. Com o Node.js fazendo todo o trabalho sozinho, o site do autor conseguiu atender a uma média de quase 900 solicitações por segundo. Com o NGINX como um servidor proxy reverso, servindo conteúdo estático, o mesmo site atendeu mais de 1600 solicitações por segundo – uma melhoria de desempenho de quase 2x.

Dobrar o desempenho lhe dá tempo para tomar medidas adicionais para acomodar o crescimento futuro, como revisar (e possivelmente melhorar) o design do seu site, otimizar o código do seu aplicativo e implantar servidores de aplicativos adicionais.

A seguir está o código de configuração que funciona para um site executado no Modulus:

servidor { ouvir 80;
nome_do_servidor static-test-47242.onmodulus.net;

raiz /mnt/app;
índice index.html index.htm;

localização /static/ {
try_files $uri $uri/ =404;
}

localização /api/ {
proxy_pass http://node-test-45750.onmodulus.net;
}
}

Este artigo detalhado de Patrick Nommensen da NGINX, Inc. explica como ele armazena em cache o conteúdo estático de seu blog pessoal, que é executado na plataforma de blog de código aberto Ghost, um aplicativo Node.js. Embora alguns detalhes sejam específicos do Ghost, você pode reutilizar grande parte do código para outros aplicativos Node.js.

Por exemplo, no bloco de localização do NGINX, você provavelmente desejará isentar algum conteúdo do armazenamento em cache. Normalmente, você não deseja armazenar em cache a interface administrativa de uma plataforma de blog, por exemplo. Aqui está o código de configuração que desabilita (ou isenta) o cache da interface administrativa do Ghost:

localização ~ ^/(?:ghost|signout) { proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://ghost_upstream;
add_header Cache-Control "sem cache, privado, sem armazenamento,
deve-revalidar, max-stale=0, pós-verificação=0, pré-verificação=0";
}

Para obter informações gerais sobre como veicular conteúdo estático, consulte o Guia de administração do NGINX Plus . O Guia do administrador inclui instruções de configuração, diversas opções para responder a tentativas bem-sucedidas ou malsucedidas de encontrar um arquivo e abordagens de otimização para obter um desempenho ainda mais rápido.

O armazenamento em cache de arquivos estáticos no servidor NGINX alivia significativamente o trabalho do servidor de aplicativos Node.js, permitindo que ele alcance um desempenho muito maior.

Dica 3 – Implemente um balanceador de carga Node.js

A verdadeira chave para um desempenho alto – ou seja, quase ilimitado – para aplicativos Node.js é executar vários servidores de aplicativos e balancear as cargas em todos eles.

O balanceamento de carga do Node.js pode ser particularmente complicado porque o Node.js permite um alto nível de interação entre o código JavaScript em execução no navegador da Web e o código JavaScript em execução no servidor de aplicativos Node.js, com objetos JSON como meio de troca de dados. Isso implica que uma determinada sessão de cliente é executada continuamente em um servidor de aplicativo específico, e a persistência da sessão é inerentemente difícil de ser alcançada com vários servidores de aplicativo.

Uma das principais vantagens da Internet e da web é seu alto grau de ausência de estado, que inclui a capacidade de solicitações de clientes serem atendidas por qualquer servidor com acesso a um arquivo solicitado. O Node.js subverte a ausência de estado e funciona melhor em um ambiente com estado, onde o mesmo servidor responde consistentemente às solicitações de quaisquer clientes específicos.

Esse requisito pode ser melhor atendido pelo NGINX Plus , em vez do NGINX Open Source. As duas versões do NGINX são bastante semelhantes, mas uma grande diferença é o suporte a diferentes algoritmos de balanceamento de carga.

O NGINX oferece suporte a métodos de balanceamento de carga sem estado:

  • Round Robin – Uma nova solicitação vai para o próximo servidor em uma lista.
  • Menos conexões – Uma nova solicitação vai para o servidor que tem o menor número de conexões ativas.
  • Hash de IP – Uma nova solicitação vai para o servidor atribuído a um hash do endereço IP do cliente.

Apenas um desses métodos, o IP Hash, envia de forma confiável as solicitações de um determinado cliente para o mesmo servidor, o que beneficia os aplicativos Node.js. No entanto, o IP Hash pode facilmente fazer com que um servidor receba um número desproporcional de solicitações, às custas de outros servidores, conforme descrito nesta postagem do blog sobre técnicas de balanceamento de carga. Este método oferece suporte ao estado em detrimento da alocação potencialmente abaixo do ideal de solicitações entre recursos do servidor.

Ao contrário do NGINX, o NGINX Plus oferece suporte à persistência de sessão . Com a persistência de sessão em uso, o mesmo servidor recebe de forma confiável todas as solicitações de um determinado cliente. As vantagens do Node.js, com sua comunicação com estado entre cliente e servidor, e do NGINX Plus, com sua capacidade avançada de balanceamento de carga, são maximizadas.

Assim, você pode usar o NGINX ou o NGINX Plus para oferecer suporte ao balanceamento de carga entre vários servidores Node.js. No entanto, somente com o NGINX Plus você provavelmente alcançará tanto o desempenho máximo de balanceamento de carga quanto a capacidade de estado compatível com o Node.js. As verificações de integridade do aplicativo e os recursos de monitoramento incorporados ao NGINX Plus também são úteis aqui.

O NGINX Plus também oferece suporte à drenagem de sessão , o que permite que um servidor de aplicativos conclua normalmente as sessões atuais após uma solicitação para que o servidor saia do serviço.

Dica 4 – Conexões Proxy WebSocket

O HTTP, em todas as versões, é projetado para comunicações “pull”, onde o cliente solicita arquivos do servidor. WebSocket é uma ferramenta para habilitar comunicações “push” e “push/pull”, onde o servidor pode enviar proativamente arquivos que o cliente não solicitou.

O protocolo WebSocket facilita o suporte a uma interação mais robusta entre cliente e servidor, ao mesmo tempo que reduz a quantidade de dados transferidos e minimiza a latência. Quando necessário, uma conexão full-duplex, com cliente e servidor iniciando e recebendo solicitações conforme necessário, é possível.

O protocolo WebSocket tem uma interface JavaScript robusta e, como tal, é uma opção natural para o Node.js como servidor de aplicativos – e, para aplicativos web com volumes moderados de transações, como servidor web também. Quando os volumes de transações aumentam, faz sentido inserir o NGINX entre os clientes e o servidor web Node.js, usando o NGINX ou o NGINX Plus para armazenar em cache arquivos estáticos e balancear a carga entre vários servidores de aplicativos.

O Node.js é frequentemente usado em conjunto com o Socket.IO – uma API WebSocket que se tornou bastante popular para uso junto com aplicativos Node.js. Isso pode fazer com que a porta 80 (para HTTP) ou a porta 443 (para HTTPS) fiquem bastante congestionadas, e a solução é usar um proxy para o servidor Socket.IO. Você pode usar o NGINX para o servidor proxy , conforme descrito acima, e também obter funcionalidades adicionais, como cache de arquivos estáticos, balanceamento de carga e muito mais.

A seguir está o código para um arquivo de aplicativo de nó server.js que escuta na porta 5000. Ele atua como um servidor proxy (não um servidor web) e encaminha solicitações para a porta apropriada:

var io = require('socket.io').listen(5000); 
io.sockets.on('connection', function (socket) {
socket.on('set nickname', function (name) {
socket.set('nickname', name, function () {
socket.emit('ready');
});
});

socket.on('msg', function () {
socket.get('nickname', function (err, name) {
console.log('Mensagem de bate-papo por ', name);
});
});
});

No seu arquivo index.html , adicione o seguinte código para se conectar ao seu aplicativo de servidor e instanciar um WebSocket entre o aplicativo e o navegador do usuário:

<script src="/socket.io/socket.io.js"></script><script>// <![CDATA[
var socket = io(); // seu código de inicialização aqui.
// ]]>
</script>

Para obter instruções completas, incluindo a configuração do NGINX, consulte nossa postagem no blog sobre como usar o NGINX e o NGINX Plus com Node.js e Socket.IO . Para mais detalhes sobre possíveis problemas de arquitetura e infraestrutura para aplicativos web desse tipo, consulte nossa postagem no blog sobre aplicativos web em tempo real e WebSocket.

Dica 5 – Implemente SSL/TLS e HTTP/2

Cada vez mais sites estão usando SSL/TLS para proteger todas as interações do usuário no site. É sua decisão se e quando fazer essa mudança, mas se e quando você fizer, o NGINX oferece suporte à transição de duas maneiras:

  1. Você pode encerrar uma conexão SSL/TLS com o cliente no NGINX, depois de configurar o NGINX como um proxy reverso. O servidor Node.js envia e recebe solicitações e conteúdo não criptografados com o servidor proxy reverso NGINX.
  2. Os primeiros indícios são de que o uso do HTTP/2 , a nova versão do protocolo HTTP, pode compensar em grande parte ou completamente a perda de desempenho imposta pelo uso do SSL/TLS. O NGINX oferece suporte a HTTP/2 e você pode encerrar HTTP/2 junto com SSL/TLS, eliminando novamente qualquer necessidade de alterações nos servidores de aplicativos Node.js.

Entre as etapas de implementação que você precisa seguir estão atualizar a URL no arquivo de configuração do Node.js, estabelecer e otimizar conexões seguras na sua configuração do NGINX e usar SPDY ou HTTP/2, se desejar. Adicionar suporte a HTTP/2 significa que as versões de navegador que suportam HTTP/2 se comunicam com seu aplicativo usando o novo protocolo; versões mais antigas de navegador continuam a usar HTTP/1.x.

O código de configuração a seguir é para um blog Ghost usando SPDY, conforme descrito aqui . Inclui recursos avançados, como grampeamento OCSP. Para considerações sobre o uso do NGINX para terminação SSL, incluindo a opção de grampeamento OCSP, veja aqui . Para uma visão geral dos mesmos tópicos, veja aqui .

Você precisa fazer apenas pequenas alterações para configurar seu aplicativo Node.js e atualizar do SPDY para o HTTP/2, agora ou quando o suporte ao SPDY acabar no início de 2016.

servidor { nome_do_servidor domínio.com;
ouvir 443 ssl spdy;
spdy_headers_comp 6;
spdy_keepalive_timeout 300;
keepalive_timeout 300;
ssl_certificate_key /etc/nginx/ssl/domain.key;
ssl_certificate /etc/nginx/ssl/domain.crt;
ssl_session_cache shared:SSL:10m; 
ssl_session_timeout 24h; 
ssl_buffer_size 1400; 
ssl_stapling ativado;
ssl_stapling_verify ativado;
ssl_trusted_certificate /etc/nginx/ssl/trust.crt;
resolver 8.8.8.8 8.8.4.4 válido=300s;
add_header Segurança-de-transporte-estrita 'idade-máx.=31536000; includeSubDomains';
add_header X-Cache $upstream_cache_status;

localização / {
proxy_cache ESTÁTICO;
proxy_cache_válido 200 30m;
proxy_cache_válido 404 1m;
proxy_pass http://ghost_upstream;
proxy_ignore_headers X-Accel-Expires Expira Controle-de-cache;
proxy_ignore_headers Definir-cookie;
proxy_hide_header Definir-cookie;
proxy_hide_header X-powered-by;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
expira 10m;
}

localização /content/images {
alias /path/to/ghost/content/images;
access_log off;
expira máx;
}

localização /assets {
alias /path/to/ghost/themes/uno-master/assets;
access_log off;
expira máx;
}

localização /public {
alias /path/to/ghost/built/public;
access_log off;
expira máx;
}

localização /ghost/scripts {
alias /path/to/ghost/core/built/scripts;
access_log off;
expira máx;
}

location ~ ^/(?:ghost|signout) { 
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://ghost_upstream;
add_header Cache-Control "sem cache, privado, sem armazenamento,
deve-revalidar, max-stale=0, pós-verificação=0, pré-verificação=0";
proxy_set_header X-Forwarded-Proto https;
}
}

Conclusão

Esta postagem do blog descreve algumas das melhorias de desempenho mais importantes que você pode fazer em seus aplicativos Node.js. Ele se concentra na adição do NGINX ao seu mix de aplicativos junto com o Node.js – usando o NGINX como um servidor proxy reverso, para armazenar em cache arquivos estáticos, para balanceamento de carga, para proxy de conexões WebSocket e para encerrar os protocolos SSL/TLS e HTTP/2.

A combinação de NGINX e Node.js é amplamente reconhecida como uma maneira de criar novos aplicativos amigáveis a microsserviços ou adicionar flexibilidade e capacidade a aplicativos baseados em SOA existentes que usam Java ou Microsoft .NET. Esta postagem ajuda você a otimizar seus aplicativos Node.js e, se desejar, a dar vida à parceria entre o Node.js e o NGINX.


"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."