As emocionantes aventuras de um sysadmin linux na procura pelo uptime perfeito!

Cluster corosync/pacemaker para balanceamento web (nginx, varnish ou apache) (or how to replace wackamole with heartbeat!)

Posted: dezembro 23rd, 2010 | Author: coredump | Filed under: Linux e Open Source | Tags: , , , , , , , , ,

Objetivo:

Construir um cluster com N máquinas rodando nginxvarnish para fornecer balanceamento de carga e cacheamento de aplicações e sites web, de forma a garantir disponibilidade e escalabilidade. O cluster será formado por N máquinas, todas ativas ao mesmo tempo em um pool de IPs que será utilizado num DNS round-robin ou balanceador via hardware para os endereços das aplicações internas. Caso um número N-1 de máquinas do cluster se torne indisponível, os IPs das máquinas indisponíveis devem ser realocados para evitar a perda de serviços.

Qual é o objetivo real aqui: servir conteúdo estático ou aplicações dinâmicas que possam ser cacheadas e balanceadas (ou seja, partes que não sejam dinâmicas ou que sejam geradas dinâmicamente mas não personalizadas o bastante para serem individuais para um determinado usuário). Usando o DNS round-robin se garante que cada IP vai receber mais ou  menos o mesmo número de requisição, não é exato mas é razoável o bastante. O problema de DNS RR é que caso um dos servidores caia aquele IP fica inacessível, e é aí que entra o cluster como esse que estou descrevendo. Caso um dos nós fique indisponível o IP dele é associado a outro nó, configurado de forma idêntica, que vai cuidar das requisições dele. Essa configuração pode ser aplicada inclusive para outros serviços que seguem uma mesma teoria.

Do ponto de vista de escalabilidade, você pode se precaver contra picos de acesso mantendo uma grande pool de IPs associados com um determinado nome, vamos supor, 12 IPs, e apenas 2 máquinas no cluster. Esses 12 endereços estarão distribuidos entre os nós de forma uniforme. No caso de um pico, basta adicionar máquinas no cluster e os endereços serão redistribuidos, sem necessidade de mudanças externas. As possibilidades são muitas.

Para isso funcionar direito, todas as máquinas do cluster tem de ter a mesma configuração e acessar os mesmos recursos. Isso pode ser feito via NFS, shared storage via NAS ou SAN, algum gerenciador de configuração como Chef ou Puppet, não importa. O que importa é que as configurações não saiam de sincronia.

Lembre-se também que conteúdo personalizado para usuários (carrinhos de compras, sites de administração de aplicações, áreas de postagens de comentários) tem de passar por servidores fora dessa estrutura ou ter alguma forma de persistência de sessão, mas isso é um problema comum a qualquer tipo de balanceamento de carga.

Arquitetura de cluster:

corosync faz parte da nova geração de ferramentas da alta disponibilidade para Linux. Podemos chamar isso tudo de heartbeat 3, mas na verdade é mais complexo que isso:  São vários projetos funcionando em uníssono para prover as funcionalidades antes disponibilizadas pelo heartbeat, e o heartbeat é agora uma das opções disponíveis para desempenhar o mesmo serviço que o corosync desempenha (comunicação entre os nós). O pacemaker por outro lado já é outra parte do sistema que cuida de gerenciar os serviços rodando, monitoramento e catalogação dos mesmos. Como eu disse, complexo. A complexidade aumentou mas as possibilidades também: os clusters não estão limitados mais a dois nós e podem ser configurados como ativos-passivos, ativos-ativos, ativos+n-ativos e quase todas as outras configurações imaginável.

Nginx + Varnish:

Faz um tempo que escolhi usar nginx+varnish na minha estrutura de balanceamento. O nginx é colocado na frente do varnish para prover algumas funcionalidades não presentes ou que seriam complexas ou custosas de se fazer no varnish, como reescrita de algumas URLS, compressão de conteúdo em gzip, adição de alguns headers de expiração (Expires:). Além disso, o nginx é utilizado para servir conteúdo multimídia como imagens, áudio e vídeo diretamente do disco sem passar pelo cache, aumentando o throughput e liberando o varnish para servir apenas conteúdo de menor tamanho. O nginx também possui um módulo especializado para servir arquivos de vídeo flv diretamente do disco que ajuda na nossa infraestrutura.

Execução:

Inicialmente eu tinha pensado em usar o wackamole, que faz redistribuição de IPs como eu queria, mas o projeto está parado a 2 anos e meio e aparentemente anda meio brigado com as interfaces no Linux 2.6. Depois de tentar resolver durante alguns dias um bug bizarro resolvi partir para a solução corosync. A instalação e configuração do Nginx e do Varnish fogem um pouco do objetivo desse post, existem vários outros na internet mostrando como montar um balanceador de carga com o nginx na frente do varnish (que eu prefiro) ou o varnish na frente do nginx (que eu acho uma solução menos escalável). A configuração inicial foi feita baseada no guia “Cluster from scratch on Fedora 11” disponível no site do pacemaker.

A primeira coisa a se fazer é garantir que os nós do cluster se encontrem corretamente na rede. É importante que os nomes estejam resolvendo corretamente noDNS e também que o arquivo /etc/hosts aponte corretamente para os ips. Certifique-se que o /etc/hosts inclua os shortnames dos servidores, o comando ping nomedoservidor (sem sufixo dns) tem de responder pelo ip correto. Além disso, uname -n deve retornar o nome do servidor também sem sufixo dns (ou seja, sem .algo), caso isso não seja o caso edite o arquivo /etc/hostname e execute:

# hostname $(cat /etc/hostname)

Os seguintes pacotes foram instalados (usando o repositório lenny-backports):

# aptitude install corosync pacemaker

E o aptitude vai se encarregar de instalar o resto das dependências, incluindo cluster-gluecluster-agents. Com os nós do cluster se falando e o software instalado, é hora de configurar o corosync. O corosync usa um endereço multicast para se comunicar entre os nós, favor prestar atenção com possíveis conflitos de porta/ips já existentes na rede. As únicas configurações alteradas do arquivo /etc/corosync/corosync.conf padrão do Debian foram: bindnetaddruse_logd,use_mgmtdconsensus.

Esta configuração tem de ser copiada para todos os nós do cluster. Depois de feito isso, inicie o corosync no primeiro nó, cheque o syslog por algum erro mais gritante e depois inicie os outros nós do cluster caso esteja tudo bem. Existem duas properties chatas que tem de ser mudadas de cara. Toda a configuração do cluster pode ser feita através de um imenso XML (ugh) ou através do comando crm que manipula o XML (legal):

# crm configure property stonith-enabled=false
# crm configure property no-quorum-policy=ignore

STONITH é o acrônimo para Shoot The Other Node In The Head, um serviço que não vamos usar nessa configuração mas é usado para serviços que tem de garantir que uma segunda cópia não rode ao mesmo tempo e para isso usam técnicas para desligar, bloquear ou ‘atirar na cabeça do outro nó’. O Debian tem essaproperty habilitada por padrão e o cluster não sobe sem o STONITH estar configurado corretamente ou a property estar desligada. O quórum já é uma propriedade interessante: ela garante que o cluster só seja considerado ‘consistente’ se tiver mais da metade dos nós ativos (isso é obviamente impossível em um cluster com 2 máquinas em que uma falha…), neste caso desabilitamos o quórum porque não importa o número de máquinas inativas, o cluster sempre vai estar ativo.

Para checar o funcionamento, use o comando crm_mon ou crm status (os dois são a mesma coisa, mas o crm_mon tem um loop que fica mostrando as informações em tempo real enquanto o crm status é one shot). A saída tem de ser algo assim:

# crm status
============
Last updated: Thu Dec 23 11:20:23 2010
Stack: openais
Current DC: node01 - partition with quorum
Version: 1.0.9-74392a28b7f31d7ddc86689598bd23114f58978b
3 Nodes configured, 3 expected votes
0 Resources configured.
============

Online: [ node01 node02 node03 ]

Depois das máquinas adicionadas e online no cluster, basta adicionar os resources que serão compartilhados, neste caso os 3 endereços IP. Usando o crm novamente (linhas quebradas para caber aqui, mas pode digitar tudo em uma linha só):

# primitive vip-1 ocf:heartbeat:IPaddr2 params ip="X.X.X.X" \ 
cidr_netmask="XX" op monitor interval="30s"

Repita isso mais duas vezes mudando vip-1 para vip-2vip-3 respectivamente para cada IP. Lembre-se que o que está sendo adicionado aqui são os IPs virtuais, não os IPs dos nós. Os parâmetros são auto-explicativos: cidr_netmask é a máscara de rede em formato CIDR do endereço, op monitor interval=“30s”vai monitorar o serviço para checar se ele está funcionando a cada 30 segundos (no caso, monitorar o IP). ocf:heartbeat:IPaddr2 é uma definição de Resource Agent, existem vários outros para vários outros serviços.

Com isso os IPs vão cada um para um nó do cluster. Isso acontece com outros serviços também. Nas palavras do project manager do corosync/pacemaker:

<beekhof> it tries to spread them out
<beekhof> regardless of what type they are
<beekhof> unless you use location constraints to tell pacemaker which ones they prefer

Isso também garante que caso mais VIPs sejam adicionados eles sejam balanceados o melhor possível entre os nós do cluster.

Checando com o crm status:

# crm status
============
Last updated: Thu Dec 23 11:43:39 2010
Stack: openais
Current DC: node01 - partition with quorum
Version: 1.0.9-74392a28b7f31d7ddc86689598bd23114f58978b
3 Nodes configured, 3 expected votes
3 Resources configured.
============

Online: [ node01 node02 node03 ]

 vip-1  (ocf::heartbeat:IPaddr2):       Started node01
 vip-2  (ocf::heartbeat:IPaddr2):       Started node02
 vip-3  (ocf::heartbeat:IPaddr2):       Started node03

A partir de agora caso um dos nós do cluster se torne indisponível o VIP rodando nele vai automaticamente ser movido para algum outro nó do cluster.

Os comandos crm configure showcrm configure show xml são interessantes para ver como as coisas são feitas.

intel.

No Comments »