Balanceamento de carga em microsserviços com Spring Cloud Netflix

Neste post, discutiremos sobre o conceito de Load Balancing e realizaremos as configurações necessárias para utilizá-lo em uma aplicação exemplo com Spring e Netflix OSS!

Por JAMILA PERIPOLLI SOUZA

 

Este é o segundo post da série onde explicamos como utilizar as tecnologias Netflix OSS com Spring Cloud para solucionar de maneira fácil e rápida os desafios trazidos pela arquitetura de microsserviços. Então se você ainda não viu o primeiro post no qual falamos sobre Service Discovery com Eureka corra e confira!

 

O que é Load Balancing?

 

Em aplicações web que possuem grande tráfego é comum encontramos arquiteturas em que um serviço possui mais de uma instância para atender à demanda. A utilização de múltiplas instâncias pode ocorrer tanto em clouds, como a AWS, quanto em ambientes tradicionais.

 

Nesse contexto, o balanceamento de carga (ou load balancing) é uma técnica que permite distribuir as requisições uniformemente entre as instâncias, assim, otimizando a utilização de recursos, diminuindo o tempo de resposta e minimizando sobrecargas.

 

Dentre as maneiras mais comuns de se realizar o balanceamento de carga, estão:

 

Server-side Load Balancing

 

Esta é a arquitetura convencional de load balancing, onde a responsabilidade de distribuir a carga fica do lado do servidor. Sendo assim, quando um cliente faz uma requisição para um determinado serviço, há um componente intermediário chamado load balancer que receberá a requisição e ficará encarregado de verificar e encaminhar a mesma para a instância do servidor que possuir menor carga naquele momento. Nesse caso o cliente não sabe qual instância responderá sua requisição.

 

Client-side Load Balancing

 

Nesta forma de realizar o balanceamento de carga o componente load balancer se torna desnecessário, pois o próprio cliente é responsável por escolher a instância para qual encaminhará sua requisição. Para que isso seja possível, o cliente deve ter conhecimento de uma lista de servidores disponíveis com quem ele pode se comunicar.

 

Por que utilizar o Ribbon?

 

Ribbon é uma biblioteca que faz parte do grupo Netflix OSS (Netflix Open Source Software) e traz funcionalidades para Client-side Load Balancing e integração com outras bibliotecas da Netflix como o Eureka.

 

O Ribbon Load Balancer trabalha com a estratégia de regras (rules) para decidir como a instância deverá ser escolhida, disponibilizando regras pré-definidas e permitindo que regras customizadas sejam implementadas. As regras já definidas na biblioteca são:

  • Round Robin: Sempre chama a próxima instância registrada na lista de servidores;
  • Response Time Weighted: Utiliza a instância com menor tempo de resposta;
  • Random Load Balancing: Escolhe uma instância aleatoriamente.

 

Dentre os principais recursos oferecido pelo Ribbon, destacam-se:

  • Funcionalidades para clouds como filtrar instâncias baseando-se em regiões (zones);
  • Integração com Service Discovery (Eureka);
  • Resistência a falhas utilizando mecanismo de ping antes de realizar a requisição real, ou utilizando o padrão Circuit Breaker;
  • REST Client integrado ao Load Balancer.

 

Mão na massa

 

Para lidarmos com o Ribbon contaremos com a biblioteca Spring Cloud Netflix que encapsula as tecnologias Netflix OSS, isso, permite que certas configurações sejam feitas através de annotations, o que facilita o trabalho.

Vamos utilizar também os projetos criados no post anterior, caso você não os tenha, poderá encontrá-los no GitHub:

 

Preparação do ambiente

 

Primeiramente, inicialize a aplicação Eureka Server executando a classe principal (main). Para conferir se a inicialização ocorreu corretamente, acesse http://localhost:8761, é esperado que encontre uma página como esta:

 

eureka-spring-netflix

 

Logo após, inicialize a aplicação “greeting-service”, ela será o serviço que iremos consumir.

Com a aplicação rodando, ao acessar http://localhost:8080/greeting deve-se obter a resposta “Hi”, “Hello” ou “Hey”.

A aplicação deve se registrar-se automaticamente no Eureka Server, para checar se isso ocorreu, recarregue a página do Eureka e confira a lista de aplicações registradas.

 

Para testar efetivamente o balanceamento de carga é interessante subir outra instância da mesma aplicação. Isso pode ser conseguido facilmente ao executar a aplicação passando a variável SERVER_PORT=8181, que trocará a porta utilizada para 8181.

 

java -jar greeting-service-0.0.1-SNAPSHOT.jar SERVER_PORT=8181



SERVER_PORT=8181 gradle bootRun

 

Feito isso, duas instâncias da aplicação devem estar registradas no Eureka, como apresentado na figura a seguir:

 

eureka-2-spring-netflix

 

Client-side Load Balancer

 

A aplicação cliente será a “user-greeting-service”, nela realizaremos as configurações para utilizar o Ribbon Load Balancer.

No arquivo application.yml adicionaremos as seguintes propriedades para o Ribbon Client “greeting-service”:

 

greeting-service:

 ribbon:

   eureka:

     enabled: false

   listOfServers: localhost:8080, localhost:8181

 

Neste momento não utilizaremos a integração com o Eureka, por isso, desabilitaremos a mesma informando o valor “false” na propriedade greeting-service.ribbon.eureka.enabbled e especificaremos uma lista de servidores na propriedade greeting-service.ribbon.listOfServers.

 

Em seguida, criaremos uma classe para realizar as configurações de nosso Ribbon Client:

 

public class RibbonConfig {



   @Bean

   public IPing ribbonPing(IClientConfig config) {

       return new NoOpPing();

   }



   @Bean

   public IRule ribbonRule(IClientConfig config) {

       return new RoundRobinRule();

   }

}

 

A interface “IPing” define a maneira com que o Ribbon realizará a checagem das instâncias que estão ativas, nesse caso, estamos definindo que isso não será realizado através da classe NoOpPing. Já a interface “IRule” é usada para definir qual regra o Ribbon utilizará para distribuir a carga, neste exemplo utilizaremos a estratégia Round Robin (vide “O que é Load Balancing?”) através da classe “RoundRobinRule”.

 

Após realizar as configurações será necessário alterar a classe de configuração do RestTemplate (RestTemplateConfig.java) adicionando a anotação @LoadBalanced no bean restTemplate indicando que o mesmo utilizará o Ribbon Load Balancer, além disso,  a anotação @RibbonClient deve ser incluída para especificar qual o nome do Ribbon Client utilizado e qual classe contém sua configuração.

 

@Configuration

@RibbonClient(name = "greeting-service", configuration = RibbonConfig.class)

public class RestTemplateConfig {



   @Bean

   @LoadBalanced

   public RestTemplate restTemplate() {

       return new RestTemplate();

   }

}

 

Também é necessário alterar o GreetingConsumer, pois, em vez de utilizar os IPs retornados pelo DiscoveryClient utilizaremos o nome do Ribbon Client na URL. Dessa forma o Ribbon saberá qual serviço desejamos chamar com base na lista de servidores configurada para aquele Ribbon Client e como efetuar a distribuição de carga da maneira que definimos.

 

public String getRandomGreeting() {

 String uri = "http://greeting-service" + greetingEndpointUri;

       String greeting = restTemplate.getForObject(uri, String.class);

       return greeting;

}

 

Após concluir, compile e execute a aplicação. Agora ao chamar o método “GreetingConsumer.getRandomGreeting()” o Load Balancer será ativado e as requisições serão feitas alternadamente para os dois servidores configurados na lista de servidores.

 

Integração com Eureka

 

Ao integrar o Ribbon ao Eureka informar uma lista de servidores se torna desnecessário, pois o próprio Eureka informará quais instâncias estão disponíveis, além disso, o Eureka também se encarrega de verificar se a instância está ativa (ping) e utiliza por padrão a estratégia Round Robin.

 

Mesmo assim ainda é possível customizar as configurações.

 

Neste exemplo utilizaremos as configurações padrão do Eureka, por isso, as configurações da classe RibbonConfig.java não são mais necessárias, assim como a lista de servidores definida no application.yml.

Para habilitar a integração com o Eureka basta trocar o valor da propriedade greeting-service.ribbon.eureka.enabled para “true”.

 

greeting-service:

 ribbon:

   eureka:

     enabled: true

 

Após habilitar a integração e executar novamente a aplicação, o comportamento deve permanecer o mesmo, efetuando as requisições alternadamente entre as instâncias do serviço.

 

Conclusão

 

A utilização de um Load Balancer na arquitetura de microsserviços é importante para reduzir o consumo de recursos. Em ambientes de cloud o Ribbon se comporta muito bem juntamente com o Eureka para realizar Client-side Load Balancing utilizando instâncias dinâmicas.

 

No próximo post da série discutiremos sobre o padrão Circuit Breaker utilizando Hystrix.

 

O código utilizado no exemplo sem integração com Service Discovery e no exemplo com integração pode ser encontrado no GitHub nas branches “ribbon” e “ribbon-eureka”, respectivamente.

 

Client Load Balancerhttps://github.com/JamilaPeripolli/user-greeting-service

 

Para mais informações sobre o Ribbon acesse sua página da Wiki.

 

Até a próxima!

Por JAMILA PERIPOLLI SOUZA

Pós graduanda em desenvolvimento para web, móveis e embarcados pelo IFPR. Desenvolve com foco em back-end. Adora aprender coisas novas (qualquer tipo de coisa).

Postado em: 13 de julho de 2018

Confira outros artigos do nosso blog

Implementando Circuit Breaker com Spring Cloud Netflix

25 de julho de 2018

Jamila Peripolli Souza

Quais os benefícios da arquitetura REST?

26 de junho de 2018

Henrique Lacerda

Desenvolvendo microsserviços com Spring Cloud Netflix

22 de junho de 2018

Jamila Peripolli Souza

Copa do Mundo: Integrando planilha Google com uma aplicação Firebase

19 de junho de 2018

Flavia Domingues

Deixe seu comentário