Balanceando carga com Apache

O Apache é um servidor web muito versátil como já temos visto, desde redução do consumo de banda com compressão e melhorias no cache, proxy reverso para proteger seus servidores web e até alta disponibilidade.

Com nosso servidor principal, seja ele qual for mas espero que seja apache :-), sob a proteção do proxy reverso tudo está ok, mas e se tivermos mais de um servidor web principais? Fazer scripts para mudar os arquivos quando um servidor cair???

Não, o apache também faz balanceamento de carga, o nome do módulo é proxy_balancer (muito justo). Com ele podemos criar um pool de servidores e redirecionar nossas consultas para ele.

Vejamos o exemplo usado no artigo sobre Proxy Reverso , vamos usá-lo como base para nosso balanceamento:

root # vi /etc/apache2/sites-available/cursos-cooperati
ProxyVia On
<VirtualHost *:80>
	ServerName cursos.cooperati.com.br
	ProxyPreserveHost	Off
        ProxyRequests           Off
	ProxyPass		/		http://cursos.cooperati.local/
	ProxyPassReverse	/		http://cursos.cooperati.local/
	ProxyPass		/includes	http://cursos.cooperati.local/includes
	ProxyPassReverse	/includes	http://cursos.cooperati.local/includes
	Redirect Permanent	/		http://cursos.cooperati.local/
	<IfModule mod_deflate.c> 
		AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript application/xml application/xhtml+xml "application/x-javascript \n\n" "text/html \n\n"
		DeflateCompressionLevel   9
	</IfModule>
</VirtualHost>

Aqui temos um proxy reverso apontando para um servidor apenas, vamos supor que tenhamos 2 servidores cursos.cooperati.local e cursos2.cooperati.local, esses servidores compartilham a mesma base de dados e sites vindos de um storage. O proxy vai balancear as requisições entre eles, sem preferência de servidor, apenas de carga.

Ficaríamos assim:

root # vi /etc/apache2/sites-available/cursos-cooperati
ProxyVia On
<VirtualHost *:80>
	ServerName cursos.cooperati.com.br
        ServerAlias www.cursos.cooperati.com.br
	ProxyPreserveHost	Off
        ProxyRequests           Off
	ProxyPass /balancer-manager !
        ProxyPass / balancer://cursos/ 
        ProxyPassReverse / http://cursos.cooperati.local
        ProxyPassReverse / http://cursos2.cooperati.local
        <Proxy balancer://cursos>
          BalancerMember http://cursos.cooperati.local
          BalancerMember http://cursos2.cooperati.local
          ProxySet lbmethod=byrequests stickysession=BALANCEID
        </Proxy>
 
        <Location /balancer-manager>
            SetHandler balancer-manager
            Order deny,allow
            Allow from 192.168.1.0/24
        </Location>
 
	<IfModule mod_deflate.c> 
		AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript application/xml application/xhtml+xml "application/x-javascript \n\n" "text/html \n\n"
		DeflateCompressionLevel   9
	</IfModule>
</VirtualHost>

Onde:
ProxyPass /balancer-manager ! – Indica que o local seusite.domínio (no nosso caso, cursos.82c.bd8.myftpupload.com) /balancer-manager (interface de verificação do balancer) não será feito repasse pelo proxy, ou seja, será processado pelo servidor apache local.

ProxyPass / balancer://cursos/ – Irá repassar as requisições do diretório principal deste virtualhost para o balancer de nome cursos.
ProxyPassReverse / http://cursos.cooperati.local – Irá repassar as requisições do diretório principal deste virtualhost para cada servidor.

– Cria o balancer de nome cursos.
BalancerMember http://cursos.cooperati.local – Define o membro do balancer
BalancerMember http://cursos2.cooperati.local – Define o membro do balancer

SetHandler balancer-manager
Order deny,allow

Allow from 192.168.1.0/24 – Define que o acesso ao balancer-manager será somente para quem vier da rede interna.

O balancer-manager é a interface de informações via web, onde é possível ver o uso de recursos e acesso aos servidores, inclusive desabilitar algum ou os dois, portanto cuidado com esse acesso. 😉

É possível utilizar pesos para os servidores de acordo com a capacidade dos hardwares e dos links, assim o servidor com hardware melhor recebe mais acessos que o outro.

Basta reiniciar o apache que teremos cada requisição sendo enviada para um servidor. Ótimo, mas se nossos sites forem estáticos, se tiver algum site com controle de sessões, como php por exemplo, vamos ter problemas. Pois estando em um servidor e dando um F5 cairíamos em outro e iríamos perder a sessão.

Para sites deste tipo usamos uma configuração um pouco diferente, veja abaixo:

root # vi /etc/apache2/sites-available/cursos-cooperati
ProxyVia On
<VirtualHost *:80>
	ServerName cursos.cooperati.com.br
        ServerAlias www.cursos.cooperati.com.br
	ProxyPreserveHost	Off
        ProxyRequests           Off
	ProxyPass /balancer-manager !
        ProxyPass / balancer://cursos/ nofailover=Off
        ProxyPassReverse / http://cursos.cooperati.local
        ProxyPassReverse / http://cursos2.cooperati.local
 
        Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
 
        <Proxy balancer://cursos>
          BalancerMember http://cursos.cooperati.local
          BalancerMember http://cursos2.cooperati.local
          ProxySet  lbmethod=bytraffic stickysession=ROUTEID
        </Proxy>
 
        <Location /balancer-manager>
            SetHandler balancer-manager
            Order deny,allow
            Allow from 192.168.1.0/24
        </Location>
 
	<IfModule mod_deflate.c> 
		AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript application/xml application/xhtml+xml "application/x-javascript \n\n" "text/html \n\n"
		DeflateCompressionLevel   9
	</IfModule>
</VirtualHost>

Onde:

ProxyPass / balancer://cursos/ nofailover=Off – Agora usamos a opção nofailover=Off para que ele detecte se um servidor não estiver respondendo e repasse para o outro.

Header add Set-Cookie “ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/” env=BALANCER_ROUTE_CHANGED – Ele irá adicionar no cookie, com a ajuda do módulo headers, um cabeçalho marcando a rota usada pelo cliente.

Assim o cliente sempre será enviado para o mesmo servidor, não importa quantos reload fizer na página, não importa quantas vezes a sessão expirar e tiver que reconectar.

ProxySet lbmethod=bytraffic stickysession=ROUTEID – Agora utilizamos um método de load balance baseado no tráfego do servidor e não na quantidade de bytes trafegados e um controle de sessão por ROTA e não por carga.

Com isso mantemos um cliente sempre no mesmo servidor, não perdendo as sessões. Quanto ao fato de um servidor cair o cliente irá perder a sessão, mas será redirecionado para o outro.

Em alguns casos o proxy, para proteger o servidor interno, reescreve a url de conexão invalidando algumas verificações de ID do PHP, para tal usamos o recurso de sessão para fazer a URL transparente para o cliente. Apesar de não recomendar em habilitar isso no php.ini, em sistemas que precisarem basta adicionar nas páginas que usam autenticação ou identificação de sessão a seguinte linha no início (dentro do PHP é claro):

ini_set(“sesion.use_trans_sid”, 1);

Com isso esse problema de falha de autenticação será resolvido. Só pra lembrar que eu não entendo de PHP, essa dica foi do meu amigo Rodrigo Maciel que é Desenvolvedor e DBA, e que está me devendo alguns artigos sobre o assunto ;-P.

Veja abaixo as telas do balancer-manager acessado via browser:

Agora selecionando um dos membros do balancer, podendo até desabilitá-lo:

Espero que esses artigos sobre apache tenham ajudado a melhorar sua infraestrutura e dado mais segurança a seus servidores. Assim diminuímos a carga de acesso e conseguimos ter uma estrutura redundante para funcionar.

  • Olá Vagner, muito bom o artigo.
    Quero aplicar algo assim aqui na empresa para garantir a disponibilidade do serviço, só tenho um dúvida.

    Caso o servidor de balanceamento de carga saia do ar, a aplicação toda fica fora? Se sim, há maneiras de evitar isso?

    Quero contratar servidores em empresas distintas para tentar prevenir problemas constantes, ex: ALOG e AWS, fazendo eles trabalharem de forma balanceada.

    Mas onde fazer o servidor de balanceamento? Como garantir a integridade? Eu não iria ficar dependendo de 1 servidor (Balanceamento) da mesma forma?

    Agradeço mais uma vez o ótimo artigo.

    • Hereck,

      O DNS aponta para o servidor de balanceamento, mas se o servidor cair redirecione o DNS para um de seus nós que volta a funcionar até resolver o problema do servidor.

      Você pode ter o servidor de balanceamento em um terceiro local, mas o ideal é que esteja na estrutura de nuvem para minimizar o consumo de banda. O que eu fiz com o balanceamento foi ter o meu firewall como servidor web externo recebendo toda a carga de acesso e ataques e ter os servidores internos protegidos e com tráfego distribuido.

  • Olá Vagner! Excelente o artigo.

    Tenho uma dúvida complementar à duvida do Hereck.

    Estou experimentando problemas com meu balanceamento. Tenho 10 nós ativos permanentemente e depois de uns 3 dias de uso o balanceamento trava o site fica em espera idefinidamente. Só resolve se reiniciar o apache.

    Os nós estão no JBoss rodando tranquilamente e somente na rede interna, o que trava é somente o balanceamento no apache. Ele não cai, simplesmente pára de redirecionar as requisições.

    Teria alguma diretriz que resolva isso?

    Por hora, colocamos como solução de contorno o restart do servidor, diariamente, na madrugada.

    Obrigado!

  • Grupo KS

    Olá Vagner,
    Poderia ajudar ?
    Quando utilizamos o Proxy Balancer, qual parâmetro devo configurar para que se um determinado node de aplicação cair o balancer não fique enviando requisições para esse servidor ?
    Explicando melhor o problema… Temos os apaches fazendo o balance para 2 servidores de Jboss onde cada um tem 2 nodes… Tive problemas em um dos servidores (caiu por completo) , o apache continuou enviando resquest para os nodes que haviam caído e assim o usuário final levando erro…
    Qual seria o parâmetro para correção disso ?

    Obrigado