BLOG | NGINX

Conexões HTTP Keepalive e desempenho da Web

NGINX-Parte-de-F5-horiz-preto-tipo-RGB
Miniatura de Owen Garrett
Owen Garrett
Publicado em 14 de março de 2014

Você já fez um benchmark de um servidor em laboratório e depois o implantou para tráfego real, apenas para descobrir que ele não consegue atingir nada próximo do desempenho de benchmark? A utilização da CPU é baixa e há muitos recursos livres, mas os clientes reclamam de tempos de resposta lentos e você não consegue descobrir como obter melhor utilização do servidor.

O que você está observando é um efeito do que podemos chamar de “HTTP heavy lifting”. Nesta postagem do blog, investigamos como o HTTP opera e como os servidores HTTP comuns processam transações HTTP. Analisamos alguns dos problemas de desempenho que podem ocorrer e vemos como o modelo orientado a eventos do NGINX o torna um proxy de aceleração muito eficaz para esses servidores HTTP. Com o NGINX, você pode transformar seu desempenho no mundo real para que ele retorne ao nível de seus benchmarks locais.

Para obter dicas sobre como ajustar o Linux e o NGINX para melhorar a velocidade e a escalabilidade dos seus aplicativos, consulte Ajustando o NGINX para desempenho em nosso blog.

Uma introdução às conexões HTTP e Keepalive

As conexões HTTP keepalive são um recurso de desempenho necessário que reduz a latência e permite que as páginas da web carreguem mais rápido.

HTTP é um protocolo simples baseado em texto. Se você não fez isso antes, dê uma olhada na saída de uma ferramenta de depuração HTTP, como a do seu navegador, e confira a estrutura padrão de solicitação e resposta:

Em sua implementação mais simples, um cliente HTTP cria uma nova conexão TCP com o servidor de destino, grava a solicitação e recebe a resposta. O servidor então fecha a conexão TCP para liberar recursos.

Este modo de operação pode ser muito ineficiente, especialmente para páginas da web complexas com um grande número de elementos ou quando os links de rede são lentos. A criação de uma nova conexão TCP requer um “handshake triplo” e sua desativação também envolve um procedimento de desligamento bidirecional. Criar e fechar conexões TCP repetidamente, uma para cada mensagem, é semelhante a desligar e discar novamente depois que cada pessoa fala em uma conversa telefônica.

O HTTP usa um mecanismo chamado conexões keepalive para manter aberta a conexão TCP entre o cliente e o servidor após a conclusão de uma transação HTTP. Se o cliente precisar realizar outra transação HTTP, ele poderá usar a conexão keepalive ociosa em vez de criar uma nova conexão TCP.

Os clientes geralmente abrem uma série de conexões TCP simultâneas com um servidor e realizam transações keepalive em todas elas. Essas conexões são mantidas abertas até que o cliente ou o servidor decida que elas não são mais necessárias, geralmente como resultado de um tempo limite de inatividade.

Os navegadores modernos geralmente abrem de 6 a 8 conexões keepalive e as mantêm abertas por vários minutos antes de expirarem. Os servidores web podem ser configurados para cronometrar essas conexões e fechá-las mais cedo.

Qual é o efeito dos Keepalives no servidor HTTP?

Se muitos clientes usarem keepalives HTTP e o servidor web tiver um limite de simultaneidade ou problema de escalabilidade, o desempenho cairá quando esse limite for atingido.

A abordagem acima foi projetada para oferecer o melhor desempenho possível para um cliente individual. Infelizmente, em um cenário de " tragédia dos comuns ", se todos os clientes operarem dessa maneira, isso pode ter um efeito prejudicial no desempenho de muitos servidores e aplicativos web comuns.

O motivo é que muitos servidores têm um limite fixo de simultaneidade. Por exemplo, em configurações comuns, o Apache HTTP Server só pode processar um número limitado de conexões TCP simultâneas: 150 com o módulo de multiprocessamento do trabalhador (MPM) e 256 com o MPM prefork . Cada conexão HTTP keepalive ociosa consome um desses slots de simultaneidade e, quando todos os slots estiverem ocupados, o servidor não poderá aceitar mais conexões HTTP.

A sabedoria convencional diz para desativar os keepalives no servidor web ou limitá-los a um tempo de vida muito curto. Eles fornecem um vetor muito simples para os ataques de negação de serviço SlowHTTPTest e Slowloris (para uma solução rápida, consulte Proteção contra negação de serviço Keep-Dead em serverfault.com).

Além disso, esses servidores web e de aplicativos normalmente alocam um thread ou processo do sistema operacional para cada conexão. Uma conexão TCP é um objeto de sistema operacional muito leve, mas um thread ou processo é muito pesado. Threads e processos requerem memória, eles devem ser gerenciados ativamente pelo sistema operacional e a "troca de contexto" entre threads ou processos consome CPU. Atribuir a cada conexão seu próprio thread ou processo é extremamente ineficiente.

O grande número de conexões simultâneas de clientes e a atribuição de um thread ou processo a cada conexão produzem o fenômeno conhecido como “HTTP heavy lifting”, em que um esforço desproporcionalmente grande é necessário para processar uma transação HTTP leve.

O que isso significa na prática?

Não são necessários muitos clientes para esgotar o limite de simultaneidade em muitos servidores web e de aplicativos contemporâneos.

Se um cliente abrir 8 conexões TCP e mantiver cada uma ativa por 15 segundos após o último uso, o cliente consumirá 8 slots de simultaneidade por 15 segundos. Se os clientes chegam ao seu site na taxa de 1 por segundo, 120 slots de simultaneidade são continuamente ocupados por conexões keepalive ociosas. Se a taxa for de 2 clientes por segundo, 240 slots de simultaneidade serão ocupados. Quando os slots estiverem esgotados, novos clientes não poderão se conectar até que as conexões existentes expirem.

Isso pode resultar em níveis de serviço muito desiguais. Os clientes que adquirirem com sucesso uma conexão keepalive poderão navegar no seu serviço quando quiserem. Clientes que tentam se conectar quando todos os slots de simultaneidade estão ocupados são bloqueados e têm que esperar em uma fila.

Por que você não vê esses efeitos durante os testes de benchmark?

Esses problemas só se manifestam em redes lentas com muitos clientes. Eles não aparecem quando se faz benchmarking com um único cliente em uma rede local rápida.

Há algumas razões pelas quais você pode não ver esses efeitos em um benchmark.

  • Se você não habilitar keepalives durante o benchmark, o cliente criará uma nova conexão TCP para cada transação (e a conexão será interrompida após a conclusão da transação). Como você provavelmente está executando o benchmark em uma rede local rápida, o benchmark é bem-sucedido e você não vê os problemas de desempenho criados pela não utilização de keepalives.
  • Se você habilitar keepalives , provavelmente poderá executar menos conexões simultâneas do que o limite do seu servidor, e seu cliente de benchmark saturará cada conexão (a usará repetidamente), levando seu servidor à sua capacidade máxima. No entanto, isso não se assemelha ao perfil real de conexões.

Observe que a maioria das ferramentas de benchmark relatam apenas transações bem-sucedidas. Conexões interrompidas devido ao esgotamento de recursos podem não ser relatadas ou podem parecer apenas uma pequena fração das conexões bem-sucedidas. Isso oculta a verdadeira natureza do problema com o tráfego do mundo real.

Quão comum é o problema?

Qualquer servidor web ou de aplicativo baseado em thread ou processo é vulnerável a limitações de simultaneidade.

Esse problema é inerente a qualquer plataforma web ou de aplicativo que atribui um thread ou processo a cada conexão. Não é fácil de detectar em um ambiente de benchmark otimizado, mas se manifesta como baixo desempenho e utilização excessiva da CPU em um ambiente do mundo real.

Existem várias medidas que você pode tomar para resolver esse problema:

  • Aumentar o número de threads ou processos – Esta é uma medida de curtíssimo prazo. Threads e processos são objetos pesados do sistema operacional e geram uma sobrecarga de gerenciamento cada vez maior à medida que mais e mais são gerados.
  • Desabilite ou limite o uso de keepalives HTTP – Isso adia o limite de simultaneidade, mas resulta em um desempenho muito pior para cada cliente.
  • Use processamento keepalive especializado – O Apache HTTP Server (servidor web) tem um MPM de eventos relativamente novo que move conexões entre threads de trabalho e um thread de eventos dedicado quando eles se movem entre os estados 'ativo' e 'inativo keepalive'. Esta pode ser uma opção se os outros módulos que você usa suportarem este MPM; observe que as conexões SSL/TLS ainda são processadas inteiramente em threads dedicados.
  • Use um modelo de processamento mais eficiente – De longe, a medida mais simples e eficaz que você pode tomar é colocar um proxy HTTP eficiente na frente de seus servidores web ou de aplicativos. Um proxy orientado a eventos como o NGINX não tem as limitações de simultaneidade descritas acima. Ele ri da cara de conexões lentas e keepalives ociosos. Além disso, ele traduz efetivamente conexões lentas do lado do cliente com várias conexões keepalive ociosas em conexões rápidas, locais e altamente eficientes no estilo benchmark, que extraem o melhor desempenho possível dos seus servidores web e de aplicativos.

Use o NGINX como um proxy HTTP acelerador

O NGINX usa uma arquitetura diferente que não sofre dos problemas de simultaneidade descritos acima. Ele transforma conexões lentas de clientes em conexões otimizadas, semelhantes a benchmarks, para extrair o melhor desempenho dos seus servidores.

O NGINX usa um modelo altamente eficiente orientado a eventos para gerenciar conexões.

Cada processo NGINX pode manipular várias conexões ao mesmo tempo. Quando uma nova conexão é aceita, a sobrecarga é muito baixa (consistindo em um novo descritor de arquivo e um novo evento para pesquisar), diferentemente do modelo por processo ou por thread descrito acima. O NGINX tem um loop de eventos muito eficaz:

Isso permite que cada processo NGINX seja facilmente dimensionado para dezenas, milhares ou centenas de milhares de conexões simultaneamente.

O NGINX então envia as solicitações para o servidor upstream, usando um pool local de conexões keepalive. Você não incorre na sobrecarga de abrir e fechar conexões TCP, e as pilhas TCP se adaptam rapidamente ao tamanho ideal da janela e aos parâmetros de repetição. Escrever solicitações e ler respostas é muito mais rápido na rede local otimizada:

O efeito líquido é que o servidor upstream se encontra conversando com um único cliente local (NGINX) por meio de uma rede rápida, e é um cliente que faz uso ideal de conexões HTTP keepalive para minimizar a configuração de conexão sem manter as conexões abertas desnecessariamente. Isso coloca o servidor de volta em seu ambiente ideal, semelhante ao de benchmark.

Com o NGINX atuando como um proxy HTTP, você vê:

  • Melhor utilização dos recursos existentes. Seus servidores web e de aplicativos podem processar mais transações por segundo porque não realizam mais o trabalho pesado de HTTP.
  • Taxas de erro reduzidas. Os tempos limite de HTTP são muito menos prováveis porque o NGINX atua como um agendador central para todos os clientes.
  • Melhor desempenho para o usuário final. Os servidores funcionam com mais eficiência e atendem às conexões com mais rapidez.

Outras maneiras pelas quais o NGINX pode acelerar serviços

Remover o fardo do trabalho pesado do HTTP é apenas uma das medidas de transformação de desempenho que o NGINX pode aplicar à sua infraestrutura de aplicativos sobrecarregada.

O recurso de cache HTTP do NGINX pode armazenar em cache respostas dos servidores upstream, seguindo a semântica de cache padrão para controlar o que é armazenado em cache e por quanto tempo. Se vários clientes solicitarem o mesmo recurso, o NGINX poderá responder a partir de seu cache e não sobrecarregar os servidores upstream com solicitações duplicadas.

O NGINX também pode descarregar outras operações do servidor upstream. Você pode descarregar as operações de compactação de dados para reduzir o uso de largura de banda, centralizar a criptografia e descriptografia SSL/TLS , executar a autenticação inicial do cliente (por exemplo, com autenticação básica HTTP , sub-solicitações para servidores de autenticação externos e JSON Web Tokens ) e aplicar todos os tipos de regras para limitar a taxa de tráfego quando necessário.

Não é seu balanceador de carga ou ADC típico

Por fim, não se esqueça de que, diferentemente de outros proxies de aceleração, balanceadores de carga ou controladores de entrega de aplicativos (ADCs), o NGINX também é um servidor web completo . Você pode usar o NGINX para fornecer conteúdo estático , encaminhar tráfego para servidores de aplicativos para Java, PHP, Python, Ruby e outras linguagens, fornecer mídia (áudio e vídeo) , integrar-se com sistemas de autenticação e segurança e até mesmo responder a transações diretamente usando regras incorporadas na configuração do NGINX.

Sem limitações de desempenho integradas, o NGINX e o NGINX Plus aproveitam ao máximo o hardware em que você os implementa, agora e no futuro.

Para experimentar o NGINX Plus, comece hoje mesmo seu teste gratuito de 30 dias ou entre em contato conosco para discutir seus casos de uso .


"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."