Balanceamento de carga

Concluído

O escalonamento horizontal colocando novas VMs online quando o tráfego aumenta é uma estratégia eficaz de dimensionamento para atender à demanda. O fato de que as VMs podem ser provisionadas rapidamente é essencial para alcançar a elasticidade. Mas colocar servidores adicionais online não será "útil", a menos que o tráfego seja distribuído entre esses servidores. De modo geral, isso ajuda o sistema a lidar com a carga aumentada. É por isso que o balanceamento de carga é tão crítico para a elasticidade quanto o ajuste dinâmico do número de recursos dedicados a uma tarefa.

A necessidade de balanceamento de carga resulta de dois requisitos básicos. Em primeiro lugar, a taxa de transferência é aprimorada pelo processamento paralelo. Se um único servidor puder lidar com 5.000 solicitações por unidade de tempo, dez servidores com carga perfeitamente balanceada poderão lidar com 50.000 solicitações por unidade de tempo. Em segundo lugar, os recursos com balanceamento de carga produzem maior disponibilidade. Em vez de encaminhar uma solicitação para um servidor que já está tendo dificuldades para acompanhar a demanda, um balanceador de carga pode direcionar a solicitação para um servidor com uma carga menor. Além disso, se um servidor ficar offline e o balanceador de carga reconhecer esse fato, o balanceador poderá direcionar solicitações para outros servidores.

O que é balanceamento de carga?

Uma forma bem conhecida de balanceamento de carga é o DNS round robin, que muitos serviços Web de grande porte usam para distribuir solicitações entre diversos servidores. Especificamente, vários servidores front-end, cada um com um endereço IP exclusivo, compartilham um nome DNS. Para balancear o número de solicitações em cada servidor Web, grandes empresas como o Google mantêm e organizam um pool de endereços IP para cada entrada DNS. Quando um cliente faz uma solicitação (por exemplo, para www.google.com), o DNS do Google seleciona um dos endereços disponíveis do pool e envia-o para o cliente. A estratégia mais simples empregada para expedir endereços IP é usar uma fila de round robin. Com esse método, depois de cada resposta DNS, a lista de endereços é permutada.

Antes do advento da nuvem, o balanceamento de carga de DNS era uma maneira simples de reduzir a latência de conexões de longa distância. O dispatcher no servidor DNS era programado para responder com o endereço IP do servidor geograficamente mais próximo ao cliente. A maneira mais fácil de fazer isso era responder com o endereço IP do pool que era numericamente o mais próximo do endereço IP do cliente. Esse método não é confiável, pois os endereços IP não são distribuídos em uma hierarquia global. As técnicas atuais são mais sofisticadas e contam com um mapeamento de endereços IP por software para locais com base em mapas físicos de ISPs (provedores de serviços de Internet). Já que esse mapeamento é implementado como uma pesquisa de software dispendiosa, esse método produz resultados melhores, mas sua computação é cara. No entanto, o custo de uma pesquisa lenta é reduzido, uma vez que a pesquisa de DNS ocorre somente quando a primeira conexão com um servidor é feita pelo cliente. Todas as comunicações subsequentes ocorrem diretamente entre o cliente e o servidor proprietário do endereço IP expedido. Um exemplo de esquema de balanceamento de carga de DNS é mostrado na Figura 9.

Figure 9: Load balancing in a cloud environment.

Figura 9: Balanceamento de carga em um ambiente de nuvem.

A desvantagem desse método está em uma falha de servidor, pois a mudança para um endereço IP diferente depende da configuração de TTL (vida útil) do cache DNS. As entradas DNS são conhecidas como tendo vida útil longa e as atualizações devem levar mais de uma semana para serem propagadas. Isso significa que é difícil "ocultar" rapidamente uma falha do servidor do cliente. A redução da validade (TTL) de um endereço IP no cache melhora isso no custo do desempenho e no aumento do número de pesquisas.

O balanceamento de carga moderno geralmente se refere ao uso de uma instância dedicada (ou de um par de instâncias) para expedir solicitações de entrada para servidores de back-end. Para cada solicitação de entrada em uma porta especificada, o balanceador de carga redireciona o tráfego para um dos servidores de back-end com base em uma estratégia de distribuição. Nesse caso, o balanceador de carga mantém os metadados de solicitação, incluindo informações como cabeçalhos de protocolo de aplicativo (por exemplo, cabeçalhos HTTP). Nessa situação, as informações obsoletas não são uma preocupação, visto que cada solicitação passa pelo balanceador de carga.

Embora todos os tipos de balanceadores de carga de rede encaminhem solicitações juntamente com qualquer contexto para os servidores de back-end, quando se trata de fornecer a resposta de volta ao cliente, eles podem empregar uma de duas estratégias básicas1:

  • Proxy – nessa abordagem, o balanceador de carga recebe a resposta do back-end e a transmite de volta para o cliente. O balanceador de carga se comporta como um proxy Web padrão e está envolvido em ambas as metades de uma transação de rede, ou seja, o encaminhamento da solicitação ao cliente e o envio da resposta.

  • Entrega TCP – nessa abordagem, a conexão TCP com o cliente é entregue ao servidor de back-end e o servidor envia a resposta diretamente para o cliente, sem passar pelo balanceador de carga.

A última dessas estratégias é ilustrada na Figura 10.

Figure 10: TCP Handoff mechanism from the dispatcher to the back-end server.

Figura 10: O mecanismo de entrega de TCP do dispatcher para o servidor de back-end.

Benefícios do balanceamento de carga

Um dos benefícios do balanceamento de carga é que ele ajuda a mascarar as falhas em um sistema. Desde que o cliente seja exposto a um único ponto de extremidade que represente vários recursos, as falhas em recursos individuais ficam ocultas do cliente, pois as solicitações são fornecidas pelo uso de outros recursos. Agora, no entanto, o balanceador de carga se torna um ponto único de falha. Se ele falhar por algum motivo, mesmo que todos os servidores de back-end ainda estejam funcionando, nenhuma solicitação de cliente será processada. Consequentemente, para obter alta disponibilidade, os balanceadores de carga geralmente são implementados em pares.

O mais importante é que o balanceamento de carga melhora a capacidade de resposta, distribuindo cargas de trabalho em vários recursos de computação na nuvem. Ter uma única instância de computação na nuvem resulta em várias limitações. Módulos anteriores abordaram a limitação física no desempenho nos casos em que mais recursos são necessários para aumentar as cargas de trabalho. Usando o balanceamento de carga, cargas de trabalho maiores são distribuídas entre vários recursos para que cada recurso possa atender às próprias solicitações de maneira independente e paralela, melhorando a taxa de transferência do aplicativo. O balanceamento de carga também melhora os tempos médios de resposta, pois há mais servidores para lidar com a carga de trabalho.

As verificações de integridade são fundamentais para implementar estratégias bem-sucedidas de balanceamento de carga. Um balanceador de carga precisa saber quando um recurso se torna indisponível, portanto, ele pode evitar o encaminhamento do tráfego para esse recurso. O monitoramento de eco de ping, no qual os servidores do balanceador de carga executa pings nos servidores com solicitações ICMP (Internet Control Message Protocol), é uma das táticas mais populares usadas para verificar a integridade de recursos específicos. Além de considerar a integridade de um recurso ao encaminhar o tráfego para ele, algumas estratégias de balanceamento de carga levam em conta outras métricas, como taxa de transferência, latência e utilização da CPU.

Os balanceadores de carga muitas vezes precisam garantir alta disponibilidade. A maneira mais simples de fazer isso é criar várias instâncias de balanceamento de carga (cada uma com um endereço IP exclusivo) e vinculá-las a um único endereço DNS. Sempre que um balanceador de carga falha por algum motivo, ele é substituído por um novo e todo o tráfego é passado para a instância de failover, com impacto mínimo no desempenho. Simultaneamente, uma nova instância do balanceador de carga pode ser configurada para substituir a que falhou e os registros DNS devem ser atualizados imediatamente.

Além de distribuir solicitações entre servidores de back-end, os balanceadores de carga geralmente empregam mecanismos para reduzir a carga nos servidores e melhorar a taxa de transferência geral. Alguns desses mecanismos incluem:

  • Descarregamento de SSL – as conexões HTTPS incorrem em custo de desempenho, pois o tráfego sobre elas é criptografado. Em vez de atender a todas as solicitações via protocolo SSL, a conexão do cliente com o balanceador de carga pode ser feita via protocolo SSL, enquanto as solicitações de redirecionamento para cada servidor são feitas por meio de HTTP não criptografado. Essa técnica reduz consideravelmente a carga nos servidores. Além disso, a segurança é mantida, desde que as solicitações de redirecionamento não sejam feitas em uma rede aberta.

  • Buffer de TCP – uma estratégia para descarregar clientes com conexões lentas para o balanceador de carga, a fim de reduzir a carga dos servidores que estão fornecendo respostas a esses clientes.

  • Cache – em determinados cenários, o balanceador de carga pode manter um cache para as solicitações mais populares (ou solicitações que podem ser manipuladas sem serem enviadas para os servidores, como conteúdo estático) para reduzir a carga nos servidores.

  • Modelagem de tráfego – um balanceador de carga pode usar essa técnica para atrasar o fluxo de pacotes ou redefinir sua prioridade, a fim de otimizar o tráfego para a configuração do servidor. Isso afeta a QoS para algumas solicitações, mas garante que a carga de entrada possa ser atendida.

É importante lembrar que o balanceamento de carga só funcionará se o balanceador de carga não estiver sob uma carga que não possa suportar. Caso contrário, o balanceador de carga se tornará o gargalo. Felizmente, os balanceadores de carga tendem a realizar pouco processamento nas solicitações que recebem e, em vez disso, dependem de servidores de back-end para fazer o trabalho real de transformar solicitações em respostas.

Expedição igualitária

Há várias estratégias de balanceamento de carga usadas na nuvem. Uma das mais comuns é a expedição igualitária, que usa um algoritmo de round robin simples para distribuir o tráfego uniformemente entre todos os nós. Ela não leva em consideração a utilização de recursos individuais no sistema, nem o tempo de execução da solicitação. Essa abordagem tenta manter cada nó no sistema ocupado e é uma das mais simples de implementar.

O AWS usa essa abordagem em sua oferta de ELB (balanceador de carga elástico). O ELB provisiona balanceadores de carga que balanceiam o tráfego entre instâncias EC2 anexadas. Os balanceadores de carga propriamente ditos são essencialmente instâncias EC2, com um serviço para rotear o tráfego de maneira específica. Como os recursos por trás do balanceador de carga são escalados horizontalmente, os endereços IP dos novos recursos são atualizados no registro DNS do balanceador de carga. Esse processo leva vários minutos para ser concluído, pois exige tempo de monitoramento e de provisionamento. Esse período de dimensionamento (o tempo de espera até que o balanceador de carga esteja pronto para lidar com a carga mais alta) é conhecido como "aquecimento" do balanceador de carga.

Os balanceadores de carga do AWS também monitoram os recursos anexados a eles para distribuição de carga de trabalho, a fim de manter uma verificação de integridade. Um mecanismo de eco de ping é usado para garantir que todos os recursos estejam íntegros. Os usuários do ELB podem configurar os parâmetros da verificação de integridade especificando os atrasos e o número de novas tentativas.

Distribuição baseada em hash

Essa abordagem tenta garantir que, durante uma sessão, as solicitações de um mesmo cliente sejam direcionadas toda vez para o mesmo servidor. Isso é obtido realizando o hash de metadados que definem cada solicitação e usando o hash para escolher um servidor. Se o hash for feito corretamente, as solicitações serão distribuídas de maneira relativamente uniforme entre os servidores. Um benefício dessa abordagem é que ela pode ser utilizada em aplicativos com reconhecimento de sessão, que podem armazenar dados de sessão na memória, em vez de gravá-los em um armazenamento de dados compartilhado, como um banco de dado ou cache Redis. Uma desvantagem é que se torna necessário criar um hash para cada solicitação, o que acrescenta um pouco de latência.

O Azure Load Balancer usa um mecanismo baseado em hash para distribuir cargas. Esse mecanismo cria um hash para cada solicitação com base no IP de origem, na porta de origem, no IP de destino, na porta de destino e no tipo de protocolo para garantir que, em circunstâncias comuns, todos os pacotes da mesma sessão atinjam o mesmo servidor de back-end. A função de hash é escolhida de modo que torna a distribuição de conexões para servidores aleatória.

Outras estratégias de balanceamento de carga

Se um determinado servidor estiver sobrecarregando o processamento de uma solicitação (ou um conjunto de solicitações), os balanceadores de carga que utilizam algoritmos de expedição de round robin ou com base em hash encaminharão solicitações para esse servidor de toda maneira. Para balancear cargas entre vários recursos, há outras estratégias mais sofisticadas e que levam a capacidade em conta. Duas das métricas mais comumente usadas para a medição da capacidade são:

  • Tempo de execução da solicitação – as estratégias com base nessa métrica usam um algoritmo de agendamento de prioridade, no qual os tempos de execução da solicitação são usados para escolher o destino para solicitações individuais. O principal desafio no uso dessa abordagem é medir com precisão os tempos de execução. Um balanceador de carga pode adivinhar tempos de execução usando (e atualizando constantemente) uma tabela na memória que armazena as diferenças entre a hora em que uma solicitação é encaminhada para cada servidor e a hora em que ela retorna.

  • Utilização de recursos – as estratégias com base nessa métrica baseiam-se na utilização de CPU para balancear a utilização entre os nós. O balanceador de carga mantém uma lista ordenada de recursos com base em sua utilização e direciona cada solicitação que ele recebe para aquele entre todos os recursos que está com a menor carga.

O balanceamento de carga é crucial para implementar serviços de nuvem escalonáveis. Sem um meio eficaz de distribuir o tráfego entre os recursos de back-end, a elasticidade obtida criando-se recursos quando eles são necessários e desprovisionando-os quando não o são é extremamente limitada.

Referências

  1. Aron, Mohit e Sanders, Darren e Druschel, Peter e Zwaenepoel, Willy (2000). "Scalable content-aware request distribution in cluster-based network servers." Anais da Conferência Técnica anual da USENIX de 2000.

Verificar seu conhecimento

1.

Considere o seguinte cenário: você está usando um balanceador de carga com um agendador de rodízio como um front-end para dois servidores Web. Um servidor Web é uma instância média que contém dois núcleos e 8 GB de RAM, enquanto o outro é uma instância grande com quatro núcleos e 16 GB de RAM. Qual dos cenários a seguir é provável?