NGINX e o algoritmo de balanceamento de carga "O Poder de Duas Escolhas"

NGINX | 12 de novembro de 2018

Novos casos de uso às vezes exigem novos algoritmos de balanceamento de carga e, no NGINX Plus R16 e no NGINX Open Source 1.15.1, adicionamos um novo método especialmente adequado para balanceadores de carga distribuídos: uma implementação do algoritmo de “duas escolhas”.

Por que precisamos de um novo algoritmo de balanceamento de carga?

Métodos clássicos de balanceamento de carga, como Menor número de conexões funcionam muito bem quando você opera um único balanceador de carga ativo que mantém uma visão completa do estado dos nós com carga balanceada. A abordagem do “poder de duas escolhas” não é tão eficaz em um único balanceador de carga, mas evita habilmente o “comportamento de manada” em cenários desfavoráveis, que pode ocorrer quando você expande a operação para vários balanceadores de carga independentes.

Esse cenário não é observado apenas ao escalar horizontalmente em ambientes de alto desempenho; ele também ocorre em ambientes conteinerizados, nos quais vários proxies fazem o balanceamento de carga do tráfego para o mesmo conjunto de instâncias de serviço.

Topologias de cluster usando balanceadores de carga distribuídos

Um exemplo comum desse cenário ocorre quando você usa o NGINX Ingress Controller para Kubernetes, com uma instância de balanceamento de carga por nó do Kubernetes.

O algoritmo é conhecido na literatura como “poder de duas escolhas”, pois foi descrito pela primeira vez na tese de doutorado de Michael Mitzenmacher, de 1996, O poder de duas escolhas no balanceamento de carga aleatório. No NGINX e no NGINX Plus, ele é implementado como uma variação do algoritmo de balanceamento de carga Aleatório, por isso também o chamamos de Aleatório com duas escolhas.

Como funciona o “poder de duas escolhas”?

Vamos começar com uma situação que talvez lhe seja familiar. Você acabou de desembarcar após um longo voo internacional e, junto com outros 400 viajantes, entrou em um movimentado saguão de desembarque.

Saguão de desembarque internacional no aeroporto
Foto: Caroline M.A Otieno – Obra própria, CC BY 2.0

Muitos aeroportos empregam orientadores no saguão de desembarque. O trabalho deles é encaminhar cada viajante para uma das várias filas dos guichês de imigração. Se pensarmos nesses orientadores como balanceadores de carga:

  • Você e os demais viajantes são solicitações, cada qual esperando ser processada o mais rápido possível.
  • Os guichês de imigração são servidores (de backend), cada um processando uma fila de solicitações.
  • Os guias maximizam a eficiência selecionando o melhor servidor para cada solicitação.
  • Os métodos disponíveis para os guias selecionarem o melhor servidor correspondem a algoritmos de balanceamento de carga.

Vamos analisar o desempenho de alguns dos possíveis algoritmos em um cenário de balanceamento de carga distribuído, como o saguão de desembarque.

Balanceamento de carga round-robin

O round robin é uma abordagem simples para o balanceamento de carga. Nessa abordagem, o guia seleciona cada fila alternadamente: o primeiro viajante é direcionado para a fila A, o próximo para a fila B e assim por diante. Quando um viajante é direcionado para a última fila, o processo recomeça na fila A. Round Robin é o algoritmo de balanceamento de carga padrão usado pelo NGINX:

Essa abordagem funciona adequadamente até que ocorra um atraso em uma das filas. Talvez algum viajante tenha perdido seus documentos ou despertado a desconfiança do agente de imigração:

A fila para de andar, mas o guia continua encaminhando viajantes para ela. O acúmulo fica cada vez maior — e isso não vai deixar os viajantes impacientes nem um pouco mais felizes!

Balanceamento de carga por menor número de conexões

Há uma abordagem muito melhor. O guia observa cada fila e, sempre que um viajante chega, encaminha-o para a fila mais curta. Esse método é semelhante ao método de balanceamento de carga Menor número de conexões do NGINX, que atribui cada nova solicitação ao servidor com o menor número de solicitações pendentes (na fila):

O balanceamento de carga por Menor Número de Conexões lida de forma bastante eficaz com viajantes que levam tempos diferentes para serem processados. Ele busca equilibrar o tamanho das filas e evita adicionar mais solicitações a uma fila que esteja parada.

Balanceamento de carga por menor tempo

Vimos que o tempo de atendimento varia de um passageiro para outro; além disso, algumas filas avançam mais rápido ou mais devagar do que outras. Por exemplo, um agente de imigração pode estar enfrentando problemas no computador, o que faz com que atenda os viajantes mais lentamente; outro pode ser extremamente rigoroso com os detalhes e fazer muitas perguntas aos viajantes. Outros agentes podem ser muito experientes e conseguir atender os viajantes com mais rapidez.

E se cada guichê de imigração tivesse um contador acima dele, indicando quantos viajantes foram atendidos, por exemplo, nos últimos 10 minutos? Assim, o orientador poderia direcionar os viajantes para uma fila com base no tamanho dela e na rapidez com que está avançando. Essa é uma maneira mais eficaz de distribuir a carga, e é isso que o algoritmo de balanceamento de carga Menor tempo do NGINX Plus faz:

Esse algoritmo é específico do NGINX Plus porque depende de dados adicionais coletados pelas métricas de Status Estendido do NGINX Plus. Ele é particularmente eficaz em ambientes de nuvem ou virtuais, nos quais a latência de cada servidor pode variar de forma imprevisível. Por isso, apenas o tamanho da fila não é suficiente para estimar o atraso.

Tudo desmorona com vários guias

Até agora, tínhamos um único guia (isto é, um balanceador de carga) com uma visão completa das filas e do tempo de resposta no saguão de desembarque. Esse guia tenta fazer a melhor escolha para cada viajante com base nas informações que possui.

Agora, considere o que acontece se tivermos vários orientadores, cada um direcionando os viajantes de forma independente. Os orientadores têm visões independentes do tamanho das filas e dos tempos de espera — eles consideram apenas os viajantes que encaminham para cada fila.

Esse cenário está sujeito a um comportamento indesejável: todos os guias percebem que uma das filas está momentaneamente menor e mais rápida e encaminham os viajantes para ela. As simulações mostram que esse “comportamento de manada” distribui os viajantes de forma desequilibrada e injusta. Da mesma forma, vários balanceadores de carga independentes podem sobrecarregar alguns servidores upstream, independentemente do algoritmo de “melhor escolha” utilizado.

O algoritmo de balanceamento de carga “O poder de duas escolhas”

A solução está no algoritmo de balanceamento de carga conhecido como “poder de duas escolhas”. Em vez de tentar fazer a melhor escolha possível com dados incompletos, com o “poder de duas escolhas” você seleciona duas filas aleatoriamente e escolhe a melhor entre elas, evitando a pior escolha.

O algoritmo de “duas escolhas” é eficiente de implementar. Você não precisa comparar todas as filas para escolher sempre a melhor opção; basta comparar duas. E, embora possa parecer contraintuitivo, ele funciona melhor em grande escala do que os algoritmos que escolhem a melhor opção. Ele evita o indesejado comportamento de manada por meio de uma abordagem simples: evitar a pior fila e distribuir o tráfego com certo grau de aleatoriedade.

Como usar o “poder de duas escolhas” com o NGINX e o NGINX Plus

No NGINX e no NGINX Plus, o método de balanceamento de carga “poder de duas escolhas” é implementado como uma variante do algoritmo Random, por isso o chamamos de Random with Two Choices.

No NGINX Open Source, o Random with Two Choices escolhe entre dois servidores selecionados aleatoriamente com base naquele que, no momento, tem menos conexões ativas. Esse é o mesmo critério de seleção usado pelo algoritmo Least Connections. (Esse também é o algoritmo padrão no NGINX Plus e pode ser configurado explicitamente adicionando o parâmetro least_conn.)

upstream service1 {    zone service1 64k;
    server 192.168.1.11;
    server 192.168.1.12;
    server 192.168.1.13;
    random two; 
}

O NGINX Plus também oferece suporte ao parâmetro least_time, que usa o mesmo critério de seleção do algoritmo Least Time. Assim como nesse algoritmo, você também pode optar por considerar:

  • O tempo para receber o cabeçalho da resposta (least_time=header)
  • O tempo para receber a resposta completa (least_time=last_byte), como no trecho a seguir. O critério de menor tempo é ideal para situações em que a latência de cada servidor upstream pode variar.
upstream service1 {    zone service1 64k;
    server 192.168.1.11;
    server 192.168.1.12;
    server 192.168.1.13;
    random two least_time=last_byte; # use header or last_byte
}

Conclusão

O NGINX e o NGINX Plus oferecem suporte a diversos métodos de balanceamento de carga; neste artigo, não abordamos os métodos determinísticos Hash e IP Hash.

Os métodos Menor Número de Conexões (e, no NGINX Plus, Menor Tempo) são muito eficazes para balancear cargas quando o balanceador de carga tem uma visão completa da carga de trabalho atribuída a cada nó e de seu desempenho anterior. Eles são menos eficazes quando vários balanceadores de carga estão distribuindo solicitações e cada um tem uma visão incompleta da carga de trabalho e do desempenho.

O método “Power of Two Choices” usa um algoritmo aleatório tendencioso e demonstrou ser eficaz no balanceamento de cargas quando cada balanceador de carga tem uma visão incompleta ou defasada. Ele evita o “comportamento de manada” apresentado por outros algoritmos que buscam tomar a melhor decisão para cada solicitação.

Considere o Random with Two Choices, a implementação do NGINX do algoritmo de “duas escolhas”, para ambientes de altíssimo desempenho e cenários de balanceamento de carga distribuído. Um bom caso de uso ocorre ao utilizar vários controladores Ingress no Kubernetes.


Compartilhar

Sobre o autor

Owen Garrett
Owen GarrettDiretor Sênior de Gestão de Produtos

Mais publicações de Owen Garrett

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
NGINX | 10/10/2024

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade

Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
NGINX | 17/06/2024

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa

Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
NGINX | 14/07/2021

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor

Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
NGINX | 02/04/2019

Distribuição segura de chaves privadas SSL com o NGINX

Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
NGINX | 24/05/2018

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX

O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
NGINX | 19/04/2016

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus

Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.