Resumo: Atualmente, a maioria dos sistemas disponíveis na Internet são críticos e precisam ficar on-line todo o tempo. O Balanceamento de Carga é uma opção para que os serviços fiquem disponíveis com uma Alta Disponibilidade e o NGINX[1] Open Source se mostra uma excelente escolha para tal cenário.
Palavras-Chaves: NGINX, Balanceamento de Carga, Persistência de Sessão, Open Source, Alta Disponibilidade.
Introdução
A alta disponibilidade (High Availability ou HA) é um recurso essencial para os serviços disponibilizados na Internet. Uma das formas de se ter HA é utilizarmos o recurso de balanceamento de carga (Load Balancing ou LB) em vários servidores backend.
O NGINX[1] Open Source já possui uma solução de LB[2] nativa através da utilização de algumas diretrizes especiais como o ip_hash[3]. Esta solução inclusive oferece o recurso de persistência de sessão[4], porém ela definitivamente não pode ser considerada um LB eficiente, pois quando diversos clientes estão atrás de um NAT[5] ou proxy ela se tornará um grande problema, ou seja, em um cenário onde poderemos ter vários clientes acessando nosso servidor com o mesmo endereço IP e o balanceamento de carga é feito tomando como base o endereço IP de origem, a carga não será distribuída de maneira homogênea entre os servidores backend, o que comprometerá toda a solução.
A partir da versão 1.7.2 do NGINX Open Source, a diretiva hash[6] foi disponibilizada e podemos utilizá-la em conjunto com outras configurações para obtermos o resultado almejado.
Como funciona?
Toda a lógica é baseada na configuração abaixo, a qual será explanada ao longo do artigo.
1 upstream us_backend {
2 hash $upstream_grp;
3 server backend1;
4 server backend2;
5 }
6
7 split_clients "client${remote_addr}${http_user_agent}${date_gmt}" $upstream_var {
8 50.0% "backend1";
9 * "backend2";
10 }
11
12 map $cookie_route $upstream_grp {
13 default $upstream_var;
14 "backend1" "backend1";
15 "backend2" "backend2";
16 }
17
18 server {
19 listen 80;
20 server_name apptest;
21
22 location / {
23 add_header Set-Cookie 'route=$upstream_grp;Path=/;HttpOnly';
24 proxy_pass http://us_backend;
25 }
26 }
Primeiro acesso do cliente: recebendo o cookie "route" do servidor
A lógica da nossa configuração para estabelecer a persistência de sessão é baseada na utilização de um cookie, por isso o comportamento do primeiro acesso realizado pelo cliente é diferente dos acessos subsequentes.
Em seu primeiro acesso, o cliente ainda não possui o cookie "route" definido em seu navegador. O NGINX irá adicionar um cookie para o cliente, mas para isso deverá ser processada a variável $upstream_grp (linha 23). Desta forma, a diretiva map[7] (linha 12) vai inicializar a variável $upstream_grp com o valor padrão (default), ou seja, o valor da variável $upstream_var (linha 13). Como o valor da variável $upstream_var também é nulo, a diretiva split_clients[8] (linha 7) é chamada para inicializá-la. A inicialização desta variável funciona como uma semente (seed) que identifica o acesso daquele cliente de forma única, pois concatena o endereço IP de origem, o user agent do navegador e a data e hora de acesso, transformando este identificador em um número dentro de um espaço de endereçamento de 32 bits.
De acordo com o nosso exemplo, 50% dos clientes ficará no espaço de endereçamento correspondente ao primeiro servidor backend (backend1) e o restante ficará no espaço de endereçamento correspondente ao segundo servidor backend (backend2). Detalhe que esta função não executa o método round-robin[4] para escolher o backend e, portanto, podem existir mais clientes acessando um servidor backend que o outro. Esta diferença na quantidade de clientes acessando os servidores tende a se equilibrar quando há vários acessos acontecendo e utilizamos valores proporcionais para cada backend. Por exemplo, utilizando-se 3 servidores backend, podemos utilizar os valores 33,3% (linha 8) e 33,3% (linha 9) .
Uma vez que a variável $upstream_var (linha 7) foi inicializada, o seu valor é retornado para a variável $upstream_grp (linha 12), e o cookie "route" é enviado ao cliente com o valor desta variável (linha 23). A partir deste momento, o cliente é direcionado para o upstream (linha 1) através da diretiva proxy_pass (linha 24), a variável $upstream_grp é então analisada pela diretiva hash[6] (linha 2), direcionando o acesso do cliente para o backend correspondente ao hash analisado.
Próximos acessos do cliente: utilizando o cookie "route" existente
Com o cookie "route" já armazenado no navegador, no acesso do cliente a variável $upstream_grp (linha 23) é inicializada logo na diretiva map (linha 12), sendo o valor do cookie "route" ($cookie_route) atribuído à variável $upstream_grp e o cliente direcionado para o upstream (linha 1) através da diretiva proxy_pass (linha 24) onde a variável $upstream_grp deverá ser analisada pela diretiva hash (linha 2) para que o acesso do cliente seja direcionado para o backend correspondente ao hash analisado.
Colocando o servidor backend em manutenção: Minimizando a perda de sessão
Se um servidor precisar de manutenção, podemos utilizar a diretiva down[9]. Como exemplo, para se colocar o primeiro servidor backend (backend1) em manutenção, alteramos a linha 3 conforme abaixo:
3 server backend1 down;
Neste caso, independentemente do valor cookie presente no navegador, o upstream direcionará o acesso para o próximo servidor válido, no caso, o backend2. Neste cenário, se o cookie possui o valor correspondente ao backend1, não conseguiremos manter a persistência de sessão, mas pelo menos garantimos o HA. Quando o servidor sair da manutenção, o upstream apontará o cliente novamente para o acesso original através do valor especificado no cookie "route".
Existe uma maneira mais trabalhosa de minimizarmos o impacto desta mudança de sessão, alterando a configuração proposta. Para isto, colocarmos o servidor desejado como down (linha 3) e comentamos as linhas do map (linha 12) e split_clients (linha 7) correspondentes ao servidor em manutenção. Temos também de alterar a proporção de acesso no split_clients (linha 7), uma vez que um dos servidores backend não mais participa da escolha do hash. Esta maneira altera o cookie do cliente, mas minimiza a perda da persistência de sessão, uma vez que todos os clientes serão redirecionados definitivamente para o outro backend.
A vantagem desta configuração é a conservação da sessão mesmo que o servidor original volte a funcionar corretamente. A desvantagem é que o balanceamento de carga poderá ficar comprometido, uma vez que os clientes que migraram para o outro backend, não mais retornarão ao seu backend original. Se a persistência de sessão não é algo muito crítico, mas desejável, podemos optar por configurar o servidor em manutenção como down ao invés de utilizarmos os comentários nas linhas correspondentes às diretivas map e split_clients.
Módulo sticky Open Source
Há um módulo sticky[10] Open Source que pode desempenhar com louvor o papel desta configuração proposta. Então, por que não utilizar este módulo? Por se tratar de um serviço crítico, desejamos utilizar o NGINX em sua forma nativa, sem módulos de terceiros. Além disso, este módulo precisa ser compilado no NGINX[1] Open Source, o que representa uma etapa a mais a ser realizada, além de representar um risco em termos de estabilidade e segurança para a aplicação.
Aumentando a segurança
Seguem algumas dicas para aumentarmos a segurança desta configuração proposta:
· Utilizar um hash único para cada nome de backend nas diretivas map e split_clients ao invés dos nomes reais dos servidores backend. Como exemplo podemos substituir o nome backend1 por 5C1ED1EB3AC25804C4DB999FB7ADAD4C;
· Utilização do cookie HttpOnly[11];
Vantagens e desvantagens desta proposta
Vantagens:
· Utilização do NGINX[1] Open Source sem a necessidade de realizar a compilação de módulos de terceiros, aumentando a segurança e estabilidade deste serviço crítico;
· Os servidores backend não precisam ser reconfigurados para utilizar este cenário;
· Os nomes dos servidores backend podem ser trocados por hashes distintos, melhorando a segurança do ambiente;
Desvantagens:
· A diretiva split_clients não faz o balanceamento exato dos clientes, pois é baseada em uma função randômica do sistema operacional, mas cumpre bem a sua função quando há uma grande quantidade de clientes se conectando;
· Dependendo do objetivo, a configuração fica onerosa para colocar um servidor backend em manutenção;
NGINX Plus
O módulo sticky já vem por padrão na versão comercial do NGINX chamada de NGINX Plus[12]. Este módulo[13] consegue desempenhar a função de persistência de sessão com a desvantagem de ter que se obter uma licença comercial.
Conclusão
A partir da versão 1.7.2 do NGINX Open Source, podemos fazer LB com persistência de sessão de forma eficiente sem a utilização de módulos de terceiros. Por se tratar de um serviço crítico que pode ser disponibilizado na Internet, a utilização do NGINX sem a compilação de módulos adicionais tende a melhorar a estabilidade e segurança deste serviço.
Referências Bibliográficas
[1] http://nginx.org/
[2] http://nginx.org/en/docs/http/load_balancing.html
[3] http://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash
[4] http://nginx.org/en/docs/http/load_balancing.html#nginx_load_balancing_with_ip_hash
[5] http://pt.wikipedia.org/wiki/Network_address_translation
[6] http://nginx.org/en/docs/http/ngx_http_upstream_module.html#hash
[7] http://nginx.org/en/docs/http/ngx_http_map_module.html#map
[8] http://nginx.org/en/docs/http/ngx_http_split_clients_module.html
[9] http://nginx.org/en/docs/http/ngx_http_upstream_module.html#server
[10] https://bitbucket.org/nginx-goodies/nginx-sticky-module-ng
[11] https://www.owasp.org/index.php/HttpOnly
[12] http://nginx.com/
[13] http://nginx.com/products/session-persistence/
Analista do Ministério Público de Minas Gerais. Bacharel em Ciência da Computação pela PUC/MG. Pós graduado em Redes e Telecomunicações pela UFMG e Administração em Redes Linux pela UFLA.
Conforme a NBR 6023:2000 da Associacao Brasileira de Normas Técnicas (ABNT), este texto cientifico publicado em periódico eletrônico deve ser citado da seguinte forma: COELHO, Fabiano Furtado Pessoa. NGINX Open Source com Balanceamento de Carga e Persistência de Sessão Conteudo Juridico, Brasilia-DF: 29 ago 2016, 04:15. Disponivel em: https://conteudojuridico.com.br/consulta/artigos/47413/nginx-open-source-com-balanceamento-de-carga-e-persistencia-de-sessao. Acesso em: 22 dez 2024.
Por: Eddie Casimiro Dutra
Por: Eddie Casimiro Dutra
Por: Christiana Bahia Andrade Pina
Por: Higor Vinicius Nogueira Jorge
Por: Higor Vinicius Nogueira Jorge
Precisa estar logado para fazer comentários.