A chave para escalar uma camada de balanceamento de carga HTTP é adicionar outra camada de balanceamento de carga de nível inferior (IP ou TCP) primeiro. Essa camada pode ser construída inteiramente com software de código aberto, embora você obtenha melhores resultados se tiver roteadores modernos.
Os fluxos (sessões TCP) devem ser hash usando cabeçalhos, como portas IP e TCP de origem / destino, para decidir a qual frontend eles vão. Você também precisa de um mecanismo para garantir que, quando um front-end morre, ele deixa de ser usado.
Existem várias estratégias, vou descrever algumas que usei na produção em sites que atendem a milhões de usuários, para que você possa ter uma idéia. Seria muito longo para explicar tudo em detalhes, mas espero que esta resposta forneça informações / indicadores suficientes para começar. Para implementar essas soluções, você precisará de alguém realmente conhecedor de redes.
É certo que o que estou descrevendo aqui é muito mais difícil de implementar do que o descrito em outras respostas, mas esse é realmente o estado da arte se você tiver um site de alto tráfego com grandes problemas de escalabilidade e requisitos de disponibilidade acima de 99,9% . Desde que você já tenha um engenheiro de rede meio onboard, custa menos configurar e executar (tanto em capex quanto opex) do que os appliances de balanceador de carga e pode ser escalado ainda mais a quase nenhum custo adicional (em comparação com a compra de um novo, ainda mais) aparelho caro quando você supera o modelo atual).
Primeira estratégia: com um firewall
Presumivelmente, você tem alguns roteadores nos quais seus uplinks do ISP estão conectados. Seu ISP fornece 2 links (ativo / passivo, usando VRRP). Nos roteadores, você também usa o VRRP e direciona o tráfego para a rede pública para um firewall. Os firewalls ( FW 1
e FW 2
abaixo) também são ativos / passivos e filtram o tráfego e enviam cada fluxo para um servidor front-end íntegro (seus balanceadores de carga HTTP FE 1
eFE 2
abaixo).
+ -------------- + + -------------- +
| Roteador ISP A | | Roteador ISP B |
+ -------------- + + -------------- +
| |
== # ====================== # == (rede pública)
| |
+ --------------- + + --------------- +
| Seu roteador A | | O seu roteador B |
+ --------------- + + --------------- +
| |
== # ===== # ========== # ===== # == (rede privada RFC 1918)
| | | |
+ ------ + + ------ + + ------ + + ------ +
| FW 1 | FE 1 | FE 2 | FW 2
+ ------ + + ------ + + ------ + + ------ +
O objetivo é ter um fluxo parecido com o seguinte:
- O ISP roteia o tráfego que vai dos seus IPs para o seu roteador ativo.
- Seus roteadores direcionam o tráfego para um VIP que usa um endereço RFC 1918 . Esse VIP pertence ao firewall ativo, bem como o VRRP. Se você usa o OpenBSD para suas necessidades de firewall, pode usar o CARP , uma alternativa sem patente ao VRRP / HSRP.
- Seu firewall aplica o filtro (por exemplo, "apenas permita 80 / tcp e 443 / tcp indo para esse endereço IP específico").
- Seu firewall também atua como um roteador e encaminha os pacotes para um front-end saudável.
- Seu front-end encerra a conexão TCP.
Agora a mágica acontece nas etapas 4 e 5, então vamos ver em mais detalhes o que eles fazem.
Seu firewall conhece a lista de front-end ( FE 1
e FE 2
) e seleciona um deles com base em um aspecto específico do fluxo (por exemplo, hash do IP e da porta de origem, entre outros cabeçalhos). Mas ele também precisa garantir que está encaminhando o tráfego para um front-end saudável, caso contrário, você trará um buraco negro. Se você usa o OpenBSD, por exemplo, pode usá-lo relayd
. o querelayd
o faz é simples: verifica a integridade de todos os seus front-end (por exemplo, enviando-lhes uma solicitação HTTP de análise) e, sempre que um front-end está íntegro, ele é adicionado a uma tabela que o firewall usa para selecionar o próximo salto dos pacotes de um determinado fluxo . Se um frontend falhar nas verificações de integridade, ele será removido da tabela e nenhum pacote será enviado a ele. Ao encaminhar um pacote para um frontend, tudo o que o firewall faz é trocar o endereço MAC de destino do pacote pelo endereço escolhido.
Na etapa 5, os pacotes do usuário são recebidos pelo seu balanceador de carga (seja Varnish, nginx ou qualquer outro). Neste ponto, o pacote ainda está destinado ao seu endereço IP público, portanto, você precisa aliasar seus VIPs na interface de loopback. Isso é chamado DSR (Direct Server Return), porque seus front-ends encerram a conexão TCP e o firewall apenas vê tráfego simplex (apenas pacotes recebidos). Seu roteador encaminhará os pacotes de saída diretamente de volta aos roteadores do ISP. Isso é especialmente bom para o tráfego HTTP, porque as solicitações tendem a ser menores que as respostas, às vezes significativamente. Só para ficar claro: isso não é uma coisa específica do OpenBSD e é amplamente usado em sites de alto tráfego.
Pegadinhas:
- Os usuários finais se conectarão diretamente aos seus servidores front-end porque você usa o DSR. Talvez já fosse o caso, mas se não, você precisa garantir que eles estejam adequadamente protegidos.
- Se você usa o OpenBSD, tenha cuidado para que o kernel seja único, pois o desempenho de um único núcleo da CPU limitará a taxa de transferência de um firewall. Pode ser um problema, dependendo do seu tipo de NIC e da taxa de pacotes que você está vendo. Existem maneiras de resolver esse problema (mais sobre isso abaixo).
Segunda estratégia: sem firewall
Essa estratégia é mais eficiente, mas mais difícil de configurar, pois depende mais das especificidades dos roteadores que você possui. A idéia é ignorar o firewall acima e fazer com que os roteadores façam todo o trabalho que os firewalls estavam fazendo.
Você precisará de roteadores que suportem ACLs L3 / L4 por porta, BGP e ECMP e PBR ( Policy Based Routing ). Somente roteadores de ponta oferecem suporte a esses recursos e geralmente possuem taxas de licenciamento extras para usar o BGP. Isso normalmente ainda é mais barato que os balanceadores de carga de hardware e também é muito mais fácil de escalar. O bom desses roteadores de ponta é que eles tendem a ter taxa de linha (por exemplo, eles sempre podem maximizar o link, mesmo em interfaces de 10 GbE, porque todas as decisões que eles tomam são feitas em ASICs em hardware).
Nas portas nas quais você tem uplinks de seu provedor de serviços de Internet, aplique a ACL que costumava estar no firewall (por exemplo, "apenas permita 80 / tcp e 443 / tcp indo para esse endereço IP específico"). Depois, cada um de seus front-end mantém uma sessão BGP com seu roteador. Você pode usar o excelente OpenBGPD (se seus frontends estiverem no OpenBSD) ou Quagga . Seu roteador fará o ECMP do tráfego para os front-end que são íntegros (porque eles estão mantendo as sessões BGP). O roteador também encaminhará o tráfego adequadamente usando o PBR.
Refinamentos
- Com a solução de par de firewall, é bom se você pode sincronizar os estados TCP entre os firewalls, para que, quando um firewall falhar, tudo falhe suavemente com o outro. Você pode conseguir isso com
pfsync
.
- Lembre-se de que
pfsync
normalmente dobrará a taxa de pacotes em seus firewalls.
- O HTTP é um protocolo sem estado, portanto, não é o fim do mundo se você redefinir todas as conexões durante um failover de firewall porque não o usa
pfsync
.
- Se você ultrapassar um único firewall, poderá usar o ECMP no seu roteador para rotear seu tráfego para mais de um par de firewall.
- Se você usa mais de um par de firewall, também pode torná-los ativos / ativos. Você pode conseguir isso fazendo com que os firewalls mantenham uma sessão BGP com os roteadores, assim como os front-end precisam manter uma no 2º design sem firewalls.
relayd
Configuração de amostra
Veja também HOWTO em https://calomel.org/relayd.html
vip = "1.2.3.4" # Seu endereço IP público
# (você pode ter mais de um, mas não precisa)
fe1 = "10.1.2.101"
fe2 = "10.1.2.102"
fe3 = "10.1.2.103"
fe4 = "10.1.2.104" # Você pode ter qualquer número de front-ends.
int_if = "em0"
tabela <fe> {$ fe1 tente novamente 2, $ fe2 tente novamente 2, $ fe3 tente novamente 2, $ fe4 tente novamente 2}
tabela <fallback> {127.0.0.1}
redirecionar tráfego da web {
ouça na porta 80 vip $
tempo limite da sessão 60
rota para <fe> verificar http "/healthcheck.html" digest "(o sha1sum de healthcheck.html)" interface $ int_if
}