Como implantar um cluster haproxy escalável e confiável no Amazon EC2?

25

Precisamos de algumas funcionalidades mais avançadas do que o ELB fornece (principalmente a inspeção L7), mas não é óbvio como lidar com coisas como batimentos cardíacos e alta disponibilidade com algo como haproxy usando EC2. Há uma alta probabilidade de precisarmos de 3 ou mais nós haproxy no cluster, portanto, uma simples pulsação entre dois nós não funcionará.

Parece que ter uma camada de pulsação na frente dos nós haproxy seria o caminho a seguir, possivelmente usando o IPVS, mas manipular as alterações de configuração conforme o cluster do EC2 muda (via alterações intencionais, como expansão ou não intencional, como a perda de um Nó EC2) parece não trivial.

De preferência, a solução abrangeria pelo menos duas zonas de disponibilidade.

Em resposta a perguntas frequentes: Não, as sessões não são complicadas. E sim, precisaremos de SSL, mas isso poderia, em teoria, ser totalmente tratado por outra configuração - somos capazes de direcionar o tráfego SSL para um local diferente do tráfego não SSL.

Don MacAskill
fonte
Estou pesquisando como fazer implantações de canários com uma porcentagem de tráfego que cresce lentamente para a nova versão do software, e estou super curiosa sobre onde você acabou com isso. Você acabou tentando alguma das sugestões de Jesper?
Iain

Respostas:

14

OK, nunca criei uma solução de balanceamento de carga da AWS com tráfego nos níveis do SmugMug, mas apenas pensando na teoria e nos serviços da AWS, algumas idéias vêm à mente.

A questão original está faltando algumas coisas que tendem a impactar o design do balanceamento de carga:

  1. Sessões complicadas ou não? É muito preferível não usar sessão complicada e permitir que todos os balanceadores de carga (LBs) usem round robin (RR) ou seleção de back-end aleatória. As seleções de RR ou de back-end aleatórias são simples, escalonáveis ​​e fornecem distribuição de carga uniforme em todas as circunstâncias.
  2. SSL ou não? Se o SSL está em uso ou não, e sobre qual porcentagem de solicitações, geralmente afeta o design do balanceamento de carga. Geralmente, é preferível encerrar o SSL o mais cedo possível, simplificar o tratamento de certificados e manter a carga da CPU SSL longe dos servidores de aplicativos da web.

Estou respondendo da perspectiva de como manter a própria camada de balanceamento de carga altamente disponível. A manutenção da HA dos servidores de aplicativos acaba de ser feita com as verificações de integridade incorporadas aos seus balanceadores de carga L7.

OK, algumas idéias que devem funcionar:

1) "O caminho da AWS":

  • A primeira camada, bem na frente, usa ELB no modo L4 (TCP / IP).
  • Segunda camada, use instâncias EC2 com seu balanceador de carga L7 de sua escolha (nginx, HAProxy, Apache etc.).

Benefícios / ideia: Os balanceadores de carga L7 podem ser bastante simples AMI EC2, todos clonados na mesma AMI e usando a mesma configuração. Assim, as ferramentas da Amazon podem lidar com todas as necessidades de alta disponibilidade: O ELB monitora os balanceadores de carga L7. Se um L7 LB morrer ou deixar de responder, o ELB e o Cloudwatch juntos geram uma nova instância automaticamente e a trazem para o pool ELB.

2) "O DNS round robin com maneira de monitoramento:"

  • Use o rodízio básico de DNS para obter uma distribuição de carga de granulação grossa em alguns endereços IP. Digamos que você publique três endereços IP para o seu site.
  • Cada um desses três IPs é um EIA (AWS Elastic IP Address), vinculado a uma instância do EC2, com um balanceador de carga L7 de sua escolha.
  • Se um EC2 L7 LB morrer, um agente de usuário compatível (navegador) deve usar apenas um dos outros IPs .
  • Configure um servidor de monitoramento externo. Monitore cada um dos 3 EIPs. Se alguém não responder, use as ferramentas de linha de comando da AWS e alguns scripts para mover o EIP para outra instância do EC2.

Benefícios / ideia: os agentes de usuário compatíveis devem alternar automaticamente para outro endereço IP, se um não responder. Portanto, no caso de uma falha, apenas 1/3 dos usuários devem ser afetados e a maioria deles não deve notar nada, pois o UA falha silenciosamente em outro IP. E sua caixa de monitoramento externo notará que um EIP não responde e corrige a situação em alguns minutos.

3) DNS RR para pares de servidores HA:

Basicamente, essa é a sugestão de Don de simples pulsação entre um par de servidores, mas simplificada para vários endereços IP.

  • Usando o RR do DNS, publique vários endereços IP para o serviço. Seguindo o exemplo acima, digamos que você publique 3 IPs.
  • Cada um desses IPs vai para um par de servidores EC2, totalizando 6 instâncias do EC2.
  • Cada um desses pares usa o Heartbeat ou outra solução de alta disponibilidade, juntamente com as ferramentas da AWS, para manter um endereço IP ativo, em uma configuração ativa / passiva.
  • Cada instância do EC2 tem seu balanceador de carga L7 de escolha instalado.

Benefícios / ideia: no ambiente totalmente virtualizado da AWS, na verdade, não é tão fácil argumentar sobre os serviços L4 e os modos de failover. Ao simplificar para um par de servidores idênticos, mantendo apenas 1 endereço IP ativo, fica mais fácil raciocinar e testar.

Conclusão: Novamente, eu realmente não tentei nada disso na produção. Apenas pelo meu pressentimento, a opção 1 com o ELB no modo L4 e as instâncias EC2 autogerenciadas como L7 LBs parecem mais alinhadas com o espírito da plataforma da AWS, e onde é mais provável que a Amazon invista e expanda mais tarde. Essa provavelmente seria minha primeira escolha.

Jesper M
fonte
11
Então, eu adoro a abordagem número 1, essa é a direção em que tenho me inclinado, mas ainda existem algumas dicas interessantes - a menos importante é que o ELB não lida com um AZ inteiro que falha muito bem (algo que já aconteceu ) A solução fácil, mas nojenta, é ter as haproxies por trás do ELB configuradas para cruzar os AZs (talvez com um cluster de backup em outro AZ). Portanto, se pelo menos um haproxy estiver ativo em cada AZ, tudo bem. Mas isso apenas mimetiza, não elimina o problema. Alguma idéia sobre esse problema?
Don MacAskill
@ Don MacAskill: Eu sei que a AWS teve alguns períodos de inatividade de serviço em larga escala, mas é difícil fazer melhor do que a confiabilidade do AZ na AWS. Mover-se para a operação multi-AZ do front-end poderia facilmente ser o primeiro passo para a operação multi-AZ de toda a pilha, e isso é uma chaleira inteira de cobras ...
Jesper M
@ Don MacAskill: Uma opção seria a resolução DNS com reconhecimento geográfico, como DynDNS Dynect -> ELB + L7 LBs dentro de um AZ, com outro ELB + L7 no modo de espera quente em outro AZ. (Além de ter conhecimento geográfico, o Dynect também possui algumas verificações de integridade.) O DynDNS tem um ótimo histórico de tempo de atividade, mas, mesmo assim, adicionar DNS com reconhecimento geográfico é outro SPOF. Se o balanceamento de carga Dynect + em 2 AZs tem melhor tempo de atividade a longo prazo do que apenas um AWS AZ não está claro para mim. Veja isso para obter uma visão geral do que eu quero dizer, sem os bancos de dados multi-AZ: dev.bizo.com/2010/05/improving-global-application.html
Jesper M
@ Don MacAskill: Apenas uma última coisa - lembre-se de que uma única instância ELB pode abranger vários AZs. Não pode se estender por regiões do EC2 . Mas se apenas o uso de ELB para L7 LB em dois AZs na mesma região for aceitável, isso seria de longe o mais simples ... Você escreveu "O ELB não lida com um AZ inteiro falhando muito bem", talvez você já saiba mais do que Eu faço.
precisa
Sim, se um ELB abrange vários AZs e tem algum tipo de falha em que não pode chegar a nenhum dos nós de back-end em um AZ (eles estão sobrecarregados, inativos, retornando 503s, o que for), os usuários finais veem esses erros - isso não acontece ' t reencaminhar para os outros AZ (s). Espero que seja planejado, mas já nos picou uma vez.
Don MacAskill
2

Se você não estiver fazendo sessões complicadas ou se estiver usando o estilo tomcat / apache (acrescente o ID do nó ao sessionid, em vez de armazenar o estado no LB), eu usaria o ELB na frente de um grupo de haproxies. O ELB possui um controle de saúde embutido, para que você possa monitorar os haproxies e remover quaisquer que estejam fora da piscina. Muito menos configuração do que o failover de pulsação.

Quanto a propagar mudanças, não tenho uma ótima resposta. O Puppet é ótimo para configuração inicial e implementação de alterações, mas para adicionar / remover nós, você tende a querer uma resposta mais rápida do que o intervalo de pesquisa de 30 minutos.

Ben Jencks
fonte
11
Essa é uma boa solução (e uma boa pergunta!) Você pode usar o Amazon SNS para propagar as alterações de configuração de maneira push. Você precisa de um sistema de notificação para adicionar / remover nós da configuração haproxy.
Rafiq Maniar
Outra opção para gerenciar servidores back-end (os que o haproxy está encaminhando) é fazer com que cada servidor back-end envie todos os haproxies ou um servidor de configuração, um registro periódico (30 segundos ou mais). Se alguém morrer, ele não será registrado rapidamente (e a haproxia deve perceber de qualquer maneira); se surgir um novo, ele será automaticamente colocado em rotação. Aparentemente, é isso que a Netflix faz.
Ben Jencks
1

Eu não o usei, mas já vi muitas pessoas mencionarem o uso de fantoches para lidar com esse tipo de problema no EC2

JamesRyan
fonte
Sim, o Puppet no EC2 torna o gerenciamento de um cluster bastante simples. Basta criar uma micro instância e usá-la como seu mestre de marionetes.
Tom O'Connor
11
Usamos fantoches em nossos datacenters, mas ainda não experimentamos o EC2. O fantoche EC2 reconhece, de alguma forma, que pode encontrar nós usando instâncias de descrição do ec2 ou algo assim e configurar / reconfigurar automaticamente com base nessa saída? E como você lidaria com o mestre de marionetes indo embora de repente?
Don MacAskill
Por que desapareceria de repente?
Tom O'Connor
Não é compatível com o EC2, mas você pode configurá-lo para que novos nós sejam marcados para assinatura quando você os inicia e usar um script de nós externos para descrevê-los. Eu escrevi um pouco de python para fazer isso com o SimpleDB (nós externos) e o SQS (fila de solicitações de assinatura de novos nós); um desenvolvedor do ubuntu escreveu scripts usando o S3: ubuntumathiaz.wordpress.com/2010/04/07/…
Ben Jencks
Se o puppetmaster vai embora de repente, ele simplesmente não executar o manifesto, ou seja, ele deixa os nós em qualquer estado em que estamos.
Ben Jencks