Já escrevemos muito sobre como você pode usar o NGINX Plus e o NGINX Open Source para balancear a carga de seus sites e aplicativos para obter disponibilidade e confiabilidade ideais. O balanceamento de carga é uma ferramenta fundamental para aumentar o desempenho dos aplicativos , entregar aplicativos em escala e implantar contêineres e microsserviços .
Já explicamos anteriormente como você pode implantar o NGINX Plus no data center (talvez junto com controladores de entrega de aplicativos legados), em contêineres e em ambientes de nuvem, incluindo Amazon Web Services (AWS), Google Cloud Platform e Microsoft Azure .
Nesta postagem, vamos nos concentrar nas técnicas de balanceamento de carga (também chamadas de métodos ou algoritmos de balanceamento de carga) no NGINX Plus e NGINX, oferecendo alguns conselhos sobre como escolher o método certo para diferentes casos de uso. O NGINX fornece quatro técnicas de balanceamento de carga ( Round Robin , Hash , IP Hash e Least Connections ), e o NGINX Plus adiciona mais uma ( Least Time ). Todos os métodos para tráfego HTTP também estão disponíveis para TCP (e UDP, no NGINX Plus Release 9 e posteriores), exceto IP Hash.
[ Editor – NGINX Plus R16 e NGINX Open Source 1.15.1 introduziram Random with Two Choices como um algoritmo de balanceamento de carga adicional. Para uma discussão, veja NGINX e o algoritmo de balanceamento de carga “Power of Two Choices” em nosso blog.]
Vamos supor que você saiba os conceitos básicos de como configurar o balanceamento de carga, mas você pode conferir estes recursos se quiser uma atualização:
Para simplificar, vamos nos concentrar no balanceamento de carga HTTP, que você configura no contexto http
. O balanceamento de carga TCP é configurado no contexto do fluxo
(assim como o balanceamento de carga UDP no NGINX Plus versão 9 e posteriores). Embora os balanceadores de carga HTTP e TCP/UDP tenham paridade de recursos, as diretivas e os parâmetros disponíveis diferem um pouco devido a diferenças inerentes entre os protocolos; para obter detalhes, consulte a documentação sobre os módulos Upstream para HTTP e TCP/UDP .
Você habilita o balanceamento de carga com dois blocos de configuração, que mostraremos em sua forma básica, sem parâmetros opcionais ou quaisquer recursos auxiliares:
O bloco do servidor
define um servidor virtual que escuta o tráfego com as características que você define e o envia por proxy para um grupo nomeado de servidores upstream. Em nossos exemplos, o servidor virtual escuta na porta padrão (80) o tráfego HTTP enviado para www.example.com e o envia por proxy para o grupo de servidores upstream chamado backend . Este bloco é o mesmo em todos os nossos exemplos.
servidor { nome_do_servidor www.exemplo.com;
localização / {
senha_do_proxy http://backend;
}
}
(NGINX Plus e NGINX também podem balancear a carga de servidores de backend FastCGI, memcached, SCGI e uwsgi. Substitua proxy_pass
pela diretiva apropriada – fastcgi_pass
, memcached_pass
, scgi_pass
ou uwsgi_pass
.)
O bloco upstream
nomeia um grupo upstream e lista os servidores que pertencem a ele, identificados por nome de host, endereço IP ou caminho de soquete de domínio UNIX. Em nossos exemplos, o grupo upstream chamado backend inclui três servidores: web1 , web2 e web3 .
O bloco upstream
é onde você especifica a técnica de balanceamento de carga, então iremos destacá-lo nas seções a seguir. Como exemplo, aqui está o bloco para o método padrão, Round Robin:
backend upstream { servidor web1;
servidor web2;
servidor web3;
}
Round Robin é a técnica de balanceamento de carga padrão para NGINX Plus e NGINX. O balanceador de carga percorre a lista de servidores upstream em sequência, atribuindo a próxima solicitação de conexão a cada um deles por vez.
Dada a seguinte configuração de exemplo do grupo upstream de backend , o balanceador de carga envia as três primeiras solicitações de conexão para web1 , web2 e web3 em ordem, a quarta para web1 , a quinta para web2 e assim por diante.
backend upstream { servidor web1;
servidor web2;
servidor web3;
}
servidor {
server_name www.example.com;
location / {
proxy_pass http://backend;
}
}
Com o método Hash, para cada solicitação o balanceador de carga calcula um hash com base na combinação de texto e variáveis NGINX que você especificar e associa o hash a um dos servidores. Ele envia todas as solicitações com esse hash para esse servidor, então esse método estabelece um tipo básico de persistência de sessão .
No exemplo a seguir, a diretiva hash
usa o esquema ( http ou https ) e o URI completo da solicitação como base para o hash:
backend upstream { hash $scheme$request_uri; servidor web1; servidor web2; servidor web3; } servidor { nome_do_servidor www.example.com; localização / { senha_do_proxy http://backend; } }
IP Hash (disponível somente para HTTP) é uma variante predefinida do método Hash, em que o hash é baseado no endereço IP do cliente. Você define isso com a diretiva ip_hash
.
backend upstream { ip_hash ; servidor web1; servidor web2; servidor web3; } servidor { server_name www.example.com; localização / { proxy_pass http://backend; } }
Se o cliente tiver um endereço IPv6, o hash será baseado no endereço inteiro. Se tiver um endereço IPv4, o hash será baseado apenas nos três primeiros octetos do endereço. Isso foi projetado para otimizar clientes ISP que recebem endereços IP dinamicamente de um intervalo de sub-rede (/24). Em caso de reinicialização ou reconexão, o endereço do cliente geralmente muda para um diferente no intervalo de rede /24, mas a conexão ainda representa o mesmo cliente, então não há razão para alterar o mapeamento para o servidor.
No entanto, se a maior parte do tráfego para seu site vier de clientes na mesma rede /24, o IP Hash não faz sentido porque ele mapeia todos os clientes para o mesmo servidor. Nesse caso (ou se você quiser fazer hash em todos os quatro octetos por outro motivo), use o método Hash com a variável $remote_addr
.
hash $endereço_remoto;
Com o método Least Connections, o balanceador de carga compara o número atual de conexões ativas que ele tem com cada servidor e envia a solicitação ao servidor com o menor número de conexões. Você o configura com a diretiva least_conn
.
backend upstream { least_conn ; servidor web1; servidor web2; servidor web3; } servidor { nome_do_servidor www.example.com; localização / { senha_do_proxy http://backend; } }
Com o método Least Time (disponível somente no NGINX Plus), o balanceador de carga combina matematicamente duas métricas para cada servidor – o número atual de conexões ativas e um tempo de resposta médio ponderado para solicitações anteriores – e envia a solicitação ao servidor com o menor valor.
Sua escolha de parâmetro na diretiva least_time
controla qual dos dois tempos de resposta é rastreado: o tempo para receber o cabeçalho de resposta ( header
) ou o tempo para receber a resposta completa ( last_byte
).
backend upstream { least_time (cabeçalho | last_byte) ; servidor web1;
servidor web2; servidor web3; } servidor { nome_do_servidor www.example.com; localização / { senha_do_proxy http://backend; } }
Notas:
Para balanceamento de carga TCP e UDP (no contexto de fluxo
), você pode escolher entre três tipos de tempo de resposta com estes parâmetros para a diretiva least_time
:
conectar
– Hora de conectar ao servidor upstreamfirst_byte
– Tempo para receber o primeiro byte de dados de respostalast_byte
– Tempo para receber o último byte de dados de respostaPara tráfego HTTP e TCP/UDP, no NGINX Plus R12 e posteriores, adicione o parâmetro inflight
para incluir conexões incompletas em cada métrica; essas conexões são incluídas por padrão em versões anteriores.
Então, como você sabe qual das técnicas de balanceamento de carga é melhor para seu site ou aplicativo?
Os padrões de tráfego variam tanto de um site para outro – e até mesmo dentro de um único site em diferentes horas do dia – que não faz sentido basear a escolha da técnica de balanceamento de carga em uma única característica (como tráfego intermitente vs. estável, conexões de curta duração vs. de longa duração e assim por diante). Dito isso, consideraremos os prós e os contras de cada método para ajudar você a restringir o leque de opções a serem consideradas.
Seja qual for o subconjunto de métodos de balanceamento de carga que você considerar, recomendamos que você os teste para ver qual funciona melhor para seu tráfego. “Melhor” geralmente significa o menor tempo para entregar respostas aos clientes, mas você pode ter critérios diferentes.
Ferramentas de gerenciamento de desempenho de aplicativos são muito úteis para esse tipo de teste – você pode criar telas personalizadas com gráficos para cada um dos servidores no grupo upstream, possibilitando compará-los em tempo real conforme os valores mudam durante o teste. Vários APMs oferecem plug-ins personalizados para NGINX Plus e NGINX, incluindo AppDynamics , Datadog , Dynatrace e New Relic .
O teste é mais simples se todos os servidores tiverem a mesma capacidade. Caso contrário, você precisa definir pesos de servidor para que máquinas com mais capacidade recebam mais solicitações. Veja Definindo pesos quando os servidores não são idênticos abaixo.
Algumas métricas a serem verificadas durante os testes são:
404
( Arquivo
não
encontrado
), por exemplo, o servidor provavelmente retorna o erro muito mais rapidamente do que entregaria o arquivo real, caso ele existisse. Com os algoritmos de balanceamento de carga de Menos Conexões e Menos Tempo, isso pode levar o balanceador de carga a favorecer um servidor que, na verdade, não está funcionando bem.Então, agora vamos analisar os benefícios e desvantagens de cada técnica de balanceamento de carga e descrever alguns casos de uso para os quais elas são particularmente adequadas. Iremos discuti-los em ordem crescente de adequação para a maioria dos casos de uso. Como uma rápida prévia: consideramos o Menor Conexões (e, para o NGINX Plus, o Menor Tempo) as melhores escolhas para a mais ampla gama de casos de uso.
As técnicas de balanceamento de carga Hash e IP Hash criam uma associação fixa entre um determinado tipo de solicitação de cliente (capturada no valor de hash) e um determinado servidor. Você pode reconhecer isso como persistência de sessão – todas as solicitações com um determinado valor de hash sempre vão para o mesmo servidor.
A maior desvantagem desses métodos é que não há garantia de que eles distribuam solicitações em números iguais entre os servidores, muito menos equilibrem a carga uniformemente. O algoritmo de hash divide uniformemente o conjunto de todos os valores de hash possíveis em “buckets”, um para cada servidor no grupo upstream, mas não há como prever se as solicitações que realmente ocorrem terão hashes distribuídos uniformemente. Suponha, por exemplo, que dez clientes estejam acessando um site, e o algoritmo IP Hash associe o hash de sete endereços IP com web1 , um com web2 e dois com web3 . O servidor web1 acaba recebendo mais que o dobro de solicitações que os outros servidores combinados.
Portanto, faz sentido usar Hash ou IP Hash quando o benefício de manter sessões supera os possíveis efeitos negativos da carga desbalanceada. Eles são a única forma de persistência de sessão disponível no NGINX. O NGINX Plus fornece três outros mecanismos de persistência de sessão que são mais sofisticados e funcionam em combinação com o balanceamento de carga real (você os configura com a diretiva sticky
). Mas você pode escolher Hash ou IP Hash mesmo com o NGINX Plus, porque os três mecanismos não funcionam nos seguintes casos:
O navegador ou aplicativo cliente não aceita cookies, e o aplicativo não tem como trabalhar com os mecanismos de persistência de sessão sem cookies. Use o método IP Hash para associar cada cliente (especificamente seu endereço IP) a um servidor específico.
Você deseja enviar solicitações de uma determinada URL para o mesmo servidor todas as vezes, para aproveitar o cache no próprio servidor. Use o método Hash com a variável $request_uri
para buscar o arquivo do mesmo servidor todas as vezes.
Por exemplo, suponha que você saiba que servir um determinado arquivo .php requer várias chamadas demoradas ao banco de dados, mas os dados buscados não mudam com frequência e, portanto, podem ser armazenados em cache. Se você direcionar todas as solicitações do arquivo para o mesmo servidor, apenas o primeiro cliente sofrerá um longo atraso por causa das chamadas ao banco de dados. Para todos os clientes subsequentes, os dados são recuperados rapidamente do cache. Outra vantagem é que apenas um servidor precisa armazenar em cache aquele conjunto específico de dados. Como você não acaba armazenando em cache os mesmos dados em todos os servidores, você pode usar caches menores.
Existem alguns casos em que o IP Hash – e o Hash quando o endereço IP do cliente está na chave – não funcionam:
Os hashes são determinísticos (o algoritmo de hash produz os mesmos resultados todas as vezes). Isso tem alguns efeitos colaterais positivos: todas as instâncias do NGINX Plus ou NGINX em uma implantação balanceiam solicitações exatamente da mesma maneira, e o mapeamento de hash para servidor persiste nas reinicializações do balanceador de carga. (Na verdade, ele é recalculado após a reinicialização, mas como o resultado é sempre o mesmo, ele efetivamente persiste.)
Por outro lado, alterar o conjunto de servidores upstream geralmente força o recálculo de pelo menos alguns dos mapeamentos, interrompendo a persistência da sessão. Você pode reduzir um pouco o número de mapeamentos recalculados:
consistente
na diretiva hash
; o NGINX Plus usa o algoritmo de hash ketama , o que resulta em menos remapeamento.Para o método IP Hash, antes de remover um servidor do grupo upstream temporariamente, adicione o parâmetro down
à sua diretiva de servidor
, como para web2 no exemplo a seguir. Os mapeamentos não são recalculados, partindo do pressuposto de que o servidor retornará ao serviço em breve.
backend upstream { ip_hash; servidor web1; servidor web2 inativo ; servidor web3; }
Conforme observado anteriormente, o Round Robin é o método de balanceamento de carga padrão no NGINX Plus e no NGINX. Isso certamente o torna o método mais fácil de escolher – você não precisa configurar nada além do próprio grupo upstream.
O consenso geral é que o Round Robin funciona melhor quando as características dos servidores e solicitações dificilmente farão com que alguns servidores fiquem sobrecarregados em relação a outros. Algumas das condições são:
O Round Robin é particularmente adequado para cenários de teste, porque garante que as solicitações sejam distribuídas entre todos os servidores e em números iguais (ou na proporção ponderada apropriada). Alguns outros métodos nem sempre distribuem o tráfego uniformemente quando o volume é baixo, o que pode distorcer os resultados do teste.
A natureza uniforme da distribuição também pode revelar se os caches estão funcionando bem e em capacidade máxima: como não há como o Round Robin enviar solicitações de um determinado arquivo para o mesmo servidor, cada servidor provavelmente acabará servindo e armazenando em cache uma ampla variedade de arquivos (e geralmente muitos dos mesmos arquivos que seus pares), o que torna o cache mais propenso a ficar cheio.
Por fim, a distribuição inicial uniforme ajuda a descobrir problemas com persistência de sessão no NGINX Plus (conforme configurado com a diretiva sticky
).
Como mencionamos acima, Least Connections é a técnica de balanceamento de carga mais adequada para a mais ampla gama de casos de uso, especialmente para tráfego de produção. Isso é apoiado por evidências anedóticas de nossos clientes. Seu desempenho é estável e previsível.
O Least Connections também distribui efetivamente a carga de trabalho entre os servidores de acordo com sua capacidade. Um servidor mais potente atende às solicitações mais rapidamente, portanto, a qualquer momento, é provável que haja um número menor de conexões ainda sendo processadas (ou até mesmo aguardando o início do processamento) do que um servidor com menos capacidade. Menos Conexões envia cada solicitação ao servidor com o menor número de conexões atuais e, portanto, é mais provável que envie solicitações a servidores mais poderosos. (No entanto, definir pesos ainda resulta em uma distribuição ainda mais eficiente de solicitações, conforme descrito em Definir pesos quando os servidores não são idênticos abaixo.)
Você pode considerar o Least Time (somente NGINX Plus) uma versão mais sensível do Least Connections. Ao incluir o tempo médio de resposta, ele leva em consideração o histórico de desempenho recente do servidor (na verdade, é uma média móvel ponderada exponencialmente, então tempos de resposta mais antigos influenciam menos a média do que tempos de resposta mais recentes).
O Least Time é particularmente adequado quando os servidores upstream têm tempos médios de resposta muito diferentes. Se, por exemplo, você tiver servidores em diferentes data centers para fins de recuperação de desastres, o Least Time tende a enviar mais solicitações aos servidores locais porque eles respondem mais rápido. Outro caso de uso são os ambientes de nuvem, onde o desempenho do servidor geralmente é muito imprevisível.
Já mencionamos várias vezes a importância de definir pesos de servidor quando os servidores no grupo upstream têm capacidades diferentes. É particularmente importante para o balanceador de carga Round Robin, que de outra forma envia o mesmo número de solicitações para cada servidor. Isso provavelmente resultará em um servidor menos potente sobrecarregado enquanto um mais potente fica parcialmente ocioso.
Para definir pesos, inclua o parâmetro weight
em uma ou mais diretivas de servidor
no bloco upstream
. O valor padrão é 1.
Você pode pensar sobre o efeito de definir pesos para as diferentes técnicas de balanceamento de carga da seguinte maneira. Tenha em mente que as descrições estão conceitualmente corretas, mas a implementação no código NGINX Plus não usa necessariamente as operações matemáticas indicadas. Aqui está o grupo upstream para nossos exemplos:
backend upstream { servidor web1 peso=6;
servidor web2 peso=3;
servidor web3;
}
Round Robin – Cada servidor recebe a porcentagem das solicitações recebidas igual ao seu peso dividido pela soma dos pesos. Em nosso exemplo, de cada dez solicitações, o web1 recebe seis (60%), o web2 recebe três (30%) e o web3 recebe um (10%).
Hash e IP Hash – Lembre-se de que, sem pesos, o algoritmo de hash divide uniformemente o conjunto de todos os valores de hash possíveis em “buckets”, um para cada servidor no grupo upstream. Com pesos, ele soma os pesos, divide o conjunto de hashes possíveis entre esse número de buckets e associa cada servidor ao número de buckets equivalente ao seu peso.
No nosso exemplo, há dez buckets, cada um com 10% dos hashes possíveis. Seis buckets (60% dos hashes possíveis) estão associados ao web1 , três buckets (30%) ao web2 e um bucket (10%) ao web3 .
Menos conexões e menos tempo – Mencionamos anteriormente que, mesmo sem pesos, esses algoritmos são bastante eficazes na distribuição de carga de trabalho entre servidores de acordo com sua capacidade. Definir pesos melhora ainda mais seu desempenho nesse aspecto.
Lembre-se de que Least Connections e Least Time enviam cada solicitação ao servidor com a menor “pontuação” (número de conexões ou uma combinação matemática de conexões e tempo, respectivamente). Quando você atribui pesos, o balanceador de carga divide a pontuação de cada servidor pelo seu peso e envia novamente a solicitação ao servidor com o menor valor.
Aqui está um exemplo de Menos Conexões com nossos pesos de amostra e o número indicado de conexões ativas: a pontuação de 100 do web1 é a mais baixa e ele recebe a solicitação, embora sua contagem de conexões de 600 seja 1,5 vezes a do web2 e mais de 4 vezes a do web3 .
Após analisar os prós e contras das técnicas de balanceamento de carga disponíveis no NGINX Plus e no NGINX, consideramos que o Least Connections (e, para o NGINX Plus, o Least Time) é o mais adequado para a mais ampla gama de casos de uso. Mas é importante que você teste vários métodos em sua implantação, porque sua combinação única de tráfego e características do servidor pode tornar outro método melhor para você.
Para experimentar o balanceamento de carga do NGINX Plus, comece hoje mesmo seu teste gratuito de 30 dias ou entre em contato conosco para discutir seus casos de uso.
Gostaríamos de saber sobre suas experiências com balanceamento de carga em diferentes casos de uso. Por favor, adicione-os na seção de comentários abaixo.
"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."