O NGINX lidera o grupo em desempenho na web, e tudo isso se deve à maneira como o software foi projetado. Enquanto muitos servidores web e servidores de application usam uma arquitetura simples baseada em processos ou encadeada, o NGINX se destaca com uma arquitetura sofisticada orientada a eventos que permite que ele seja dimensionado para centenas de milhares de conexões simultâneas em hardware moderno.
O infográfico Inside NGINX analisa detalhadamente a arquitetura de processo de alto nível para ilustrar como o NGINX lida com múltiplas conexões dentro de um único processo. Este blog explica como tudo funciona com mais detalhes.
Para entender melhor esse design, você precisa entender como o NGINX é executado. O NGINX tem um processo mestre (que executa operações privilegiadas, como leitura de configuração e vinculação a portas) e vários processos de trabalho e auxiliares.
# service nginx restart* Restarting nginx
# ps -ef --forest | grep nginx
root 32475 1 0 13:36 ? 00:00:00 nginx: master process /usr/sbin/nginx
-c /etc/nginx/nginx.conf
nginx 32476 32475 0 13:36 ? 00:00:00 _ nginx: worker process
nginx 32477 32475 0 13:36 ? 00:00:00 _ nginx: worker process
nginx 32479 32475 0 13:36 ? 00:00:00 _ nginx: worker process
nginx 32480 32475 0 13:36 ? 00:00:00 _ nginx: worker process
nginx 32481 32475 0 13:36 ? 00:00:00 _ nginx: cache manager process
nginx 32482 32475 0 13:36 ? 00:00:00 _ nginx: cache loader process
Neste servidor de quatro núcleos, o processo mestre NGINX cria quatro processos de trabalho e alguns processos auxiliares de cache que gerenciam o cache de conteúdo no disco.
A base fundamental de qualquer application Unix é o thread ou processo. (Da perspectiva do sistema operacional Linux, threads e processos são praticamente idênticos; a principal diferença é o grau em que eles compartilham memória.) Um thread ou processo é um conjunto independente de instruções que o sistema operacional pode programar para execução em um núcleo de CPU. A maioria dos applications complexos executa vários threads ou processos em paralelo por dois motivos:
Processos e threads consomem recursos. Cada um deles usa memória e outros recursos do sistema operacional e precisa ser trocado entre os núcleos (uma operação chamada de troca de contexto ). A maioria dos servidores modernos pode lidar com centenas de pequenos threads ou processos ativos simultaneamente, mas o desempenho cai seriamente quando a memória se esgota ou quando uma alta carga de E/S causa um grande volume de trocas de contexto.
A maneira comum de projetar applications de rede é atribuir um thread ou processo a cada conexão. Essa arquitetura é simples e fácil de implementar, mas não é escalável quando o application precisa lidar com milhares de conexões simultâneas.
O NGINX usa um modelo de processo previsível que é ajustado aos recursos de hardware disponíveis:
A configuração NGINX recomendada na maioria dos casos – executando um processo de trabalho por núcleo de CPU – faz o uso mais eficiente dos recursos de hardware. Você o configura definindo o parâmetro auto
na diretiva worker_processes
:
worker_processes auto;
Quando um servidor NGINX está ativo, somente os processos de trabalho ficam ocupados. Cada processo de trabalho manipula múltiplas conexões de forma não bloqueante, reduzindo o número de trocas de contexto.
Cada processo de trabalho é de thread único e executado de forma independente, capturando novas conexões e processando-as. Os processos podem se comunicar usando memória compartilhada para dados de cache compartilhado, dados de persistência de sessão e outros recursos compartilhados.
Cada processo de trabalho do NGINX é inicializado com a configuração do NGINX e recebe um conjunto de soquetes de escuta do processo mestre.
Os processos de trabalho do NGINX começam esperando por eventos nos soquetes de escuta ( accept_mutex e fragmentação de soquete do kernel ). Os eventos são iniciados por novas conexões de entrada. Essas conexões são atribuídas a uma máquina de estado – a máquina de estado HTTP é a mais comumente usada, mas o NGINX também implementa máquinas de estado para tráfego de fluxo (TCP bruto) e para vários protocolos de e-mail (SMTP, IMAP e POP3).
A máquina de estados é essencialmente o conjunto de instruções que informam ao NGINX como processar uma solicitação. A maioria dos servidores web que executam as mesmas funções que o NGINX usam uma máquina de estado semelhante – a diferença está na implementação.
Pense na máquina de estados como as regras do xadrez. Cada transação HTTP é um jogo de xadrez. De um lado do tabuleiro de xadrez está o servidor web – um grande mestre que pode tomar decisões muito rapidamente. Do outro lado está o cliente remoto – o navegador da web que acessa o site ou application por meio de uma rede relativamente lenta.
No entanto, as regras do jogo podem ser muito complicadas. Por exemplo, o servidor web pode precisar se comunicar com outras partes (fazendo proxy para um application upstream) ou falar com um servidor de autenticação. Módulos de terceiros no servidor web podem até mesmo estender as regras do jogo.
Lembre-se de nossa descrição de um processo ou thread como um conjunto independente de instruções que o sistema operacional pode programar para execução em um núcleo de CPU. A maioria dos servidores e applications da web usa um modelo de processo por conexão ou thread por conexão para jogar o jogo de xadrez. Cada processo ou thread contém as instruções para jogar um jogo até o final. Durante o tempo em que o processo é executado pelo servidor, ele passa a maior parte do tempo "bloqueado" – esperando que o cliente conclua seu próximo movimento.
O ponto importante a lembrar é que cada conexão HTTP ativa (cada jogo de xadrez) requer um processo ou thread dedicado (um grande mestre). Esta arquitetura é simples e fácil de estender com módulos de terceiros (‘novas regras’). No entanto, há um enorme desequilíbrio: a conexão HTTP bastante leve, representada por um descritor de arquivo e uma pequena quantidade de memória, mapeia para um thread ou processo separado, um objeto de sistema operacional muito pesado. É uma conveniência de programação, mas é um desperdício enorme.
Talvez você já tenha ouvido falar de jogos de exibição simultânea , onde um grande mestre de xadrez joga contra dezenas de oponentes ao mesmo tempo?
É assim que um processo de trabalho NGINX joga “xadrez”. Cada trabalhador (lembre-se – geralmente há um trabalhador para cada núcleo da CPU) é um grande mestre que pode jogar centenas (na verdade, centenas de milhares) de jogos simultaneamente.
Um trabalhador nunca bloqueia o tráfego de rede, esperando que seu “oponente” (o cliente) responda. Após fazer sua jogada, o trabalhador imediatamente prossegue para outros jogos onde há jogadas esperando para serem processadas, ou dá as boas-vindas a novos jogadores.
O NGINX é muito bem dimensionado para suportar centenas de milhares de conexões por processo de trabalho. Cada nova conexão cria outro descritor de arquivo e consome uma pequena quantidade de memória adicional no processo de trabalho. Há muito pouca sobrecarga adicional por conexão. Os processos NGINX podem permanecer fixados nas CPUs. Trocas de contexto são relativamente pouco frequentes e ocorrem quando não há trabalho a ser feito.
Na abordagem de bloqueio de conexão por processo, cada conexão requer uma grande quantidade de recursos adicionais e sobrecarga, e as trocas de contexto (troca de um processo para outro) são muito frequentes.
Para uma explicação mais detalhada, confira este artigo sobre a arquitetura NGINX, por Andrew Alexeev, vice-presidente de desenvolvimento corporativo e cofundador da NGINX, Inc.
Com o ajuste apropriado do sistema , o NGINX pode ser dimensionado para lidar com centenas de milhares de conexões HTTP simultâneas por processo de trabalho e pode absorver picos de tráfego (um fluxo de novos jogos) sem perder o ritmo.
A arquitetura de processo do NGINX, com um pequeno número de processos de trabalho, permite uma atualização muito eficiente da configuração e até mesmo do próprio binário NGINX.
Atualizar a configuração do NGINX é uma operação muito simples, leve e confiável. Normalmente, isso significa apenas executar o comando nginx
-s
reload
, que verifica a configuração no disco e envia ao processo mestre um sinal SIGHUP.
Quando o processo mestre recebe um SIGHUP, ele faz duas coisas:
Esse processo de recarga pode causar um pequeno pico no uso da CPU e da memória, mas geralmente é imperceptível em comparação com a carga de recursos de conexões ativas. Você pode recarregar a configuração várias vezes por segundo (e muitos usuários do NGINX fazem exatamente isso). Muito raramente, surgem problemas quando há muitas gerações de processos de trabalho do NGINX aguardando o fechamento das conexões, mas mesmo esses são resolvidos rapidamente.
O processo de atualização binária do NGINX atinge o Santo Graal da alta disponibilidade: você pode atualizar o software rapidamente, sem nenhuma conexão perdida, tempo de inatividade ou interrupção no serviço.
O processo de atualização binária é semelhante em abordagem ao recarregamento suave da configuração. Um novo processo mestre NGINX é executado em paralelo com o processo mestre original, e eles compartilham os soquetes de escuta. Ambos os processos estão ativos e seus respectivos processos de trabalho lidam com o tráfego. Você pode então sinalizar ao velho mestre e seus trabalhadores para que saiam graciosamente.
Todo o processo é descrito com mais detalhes em Controlando o NGINX .
O infográfico Inside NGINX fornece uma visão geral de alto nível de como o NGINX funciona, mas por trás dessa explicação simples há mais de dez anos de inovação e otimização que permitem que o NGINX ofereça o melhor desempenho possível em uma ampla variedade de hardware, mantendo a segurança e a confiabilidade que os applications da web modernos exigem.
Se você quiser ler mais sobre as otimizações no NGINX, confira estes excelentes recursos:
SO_REUSEPORT
)"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."