
Dando continuidade à série de posts sobre desenvolvimento de microsserviços utilizando as bibliotecas Spring Cloud Netflix, este é o terceiro post da série onde o objetivo é abordar o tratamento de falhas durante requisições em uma arquitetura de sistemas distribuídos utilizando o padrão Circuit Breaker.
Não deixe de conferir o post anterior onde discutimos sobre Load Balancing com Ribbon.
O que é Circuit Breaker?
Em uma arquitetura monolítica, a comunicação entre os componentes do sistema geralmente não apresenta riscos por ser feita através de chamadas de métodos. No entanto, em uma arquitetura de microsserviços, essa comunicação é realizada entre componentes que podem estar em outra aplicação, outro computador ou até mesmo em outra região do planeta.
Nessa situação, não é possível garantir que a comunicação seja realizada com sucesso, pois, podem ocorrer erros como problemas na conexão com a internet, indisponibilidade do serviço ou alta latência para responder às requisições. Problemas como esses, podem causar uma reação em cadeia, fazendo com que os serviços que dependem dessa comunicação gastem recursos tentando restabelecê-la e fiquem aguardando a resposta por muito tempo, ou que até mesmo falhem.
Uma das maneiras de amenizar esses possíveis problemas é implementando o padrão Circuit Breaker, que trabalha com o monitoramento das chamadas. Neste padrão, quando é detectado que um serviço não está respondendo adequadamente, às requisições recebem uma resposta dada por um comportamento predefinido.
O Circuit Breaker também trabalha com o conceito de estados, sendo eles:
Circuito fechado: Neste estado, o Circuit Breaker entende que o serviço está respondendo apropriadamente, então, permite que as requisições do cliente sejam direcionadas ao serviço. Caso o serviço ultrapasse um número limite de falhas, o Circuit Breaker entrará no estado aberto;
Circuito aberto: Este é o estado em que o Circuit Breaker entende que o serviço está indisponível ou não está respondendo adequadamente, por isso, não permite que as requisições sejam feitas e causem falhas. Na maior parte das vezes, neste estado as requisições caem em um método de fallback. Após um determinado período de tempo o Circuit Breaker passará para o estado semi-aberto;
Circuito semi-aberto: Após o período de tempo gasto em estado aberto, o Circuit Breaker permite que uma ou um pequeno grupo de requisições sejam feitas para o serviço. Se o mesmo prover uma resposta de sucesso o Circuit Breaker passa para o estado fechado entendendo que a falha foi corrigida, caso contrário volta para o estado aberto e aguarda novamente.
Por que utilizar o Hystrix?
O Hystrix é mais uma solução do grupo Netflix OSS, ele implementa o padrão Circuit Breaker e visa lidar com as possíveis falhas nas chamadas entre microsserviços. Dentre suas vantagens estão:
Controlar o número de threads de chamadas para dependências externas;
Encapsular as requisições em um objeto HystrixCommand que atua como um proxy e comumente é executado em threads separadas;
Permitir a configuração de um tempo limite para espera de respostas das requisições;
Quando em estado aberto, encaminhar as requisições para um método de fallback predefinido;
Fornecer dados para monitoramento e alertas quase em tempo real;
Permitir que as configurações sejam feitas separadamente para cada HystrixCommand.
Mão na massa
Implementaremos agora o padrão Circuit Breaker utilizando as bibliotecas Spring Cloud Netflix. Iremos reaproveitar os projetos utilizados nos posts anteriores, portanto se você ainda não os tem, pode encontrá-los no GitHub:
Preparação do ambiente
Como de costume, a primeira coisa a se fazer é executar a aplicação Eureka Server para que as outras aplicações possam registrar suas instâncias. A aplicação utiliza a porta
8761 por padrão, sendo acessível após a inicialização em http://localhost:8761.

Iniciaremos também a execução da aplicação “greeting-service”, que fornecerá o serviço a ser consumido, ela representará um serviço sujeito a falhas. Após sua inicialização, confira a página do Eureka para confirmar que ela se registrou com sucesso, como na imagem a seguir:

Essa aplicação, possui um endpoint mapeado em “/greeting” que ao receber uma requisição Get retorna aleatoriamente as saudações: “Hi”, “Hey” ou “Hello”.
Circuit Breaker
Na aplicação “
user-greeting-service” existe uma classe chamada GreetingConsumer que utiliza um
RestTemplate para fazer chamadas para a aplicação “greeting-service” e obter uma saudação aleatória. Este é um potencial ponto de falhas da aplicação, portanto, vamos implementar o Circuit Breaker para essa chamada.Primeiramente, para utilizar o Hystrix será necessário adicionar a seguinte dependência ao projeto:
Maven:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
Gradle:
compile('org.springframework.cloud:spring-cloud-starter-netflix-hystrix')
Para que o Spring saiba que esta aplicação possui circuit breakers e permitir o monitoramento das chamadas adicione a anotação @EnableCircuitBreaker na classe principal:
@SpringBootApplication @EnableDiscoveryClient @EnableCircuitBreaker public class UserGreetingServiceApplication { public static void main(String[] args) { SpringApplication.run(UserGreetingServiceApplication.class, args); } }
No método
getRandomGreeting() da classe GreetingConsumer, vamos adicionar a anotação @HystrixCommand e informar qual será o nome do método de
fallback através do atributo “fallbackMethod”.Também criaremos o método de fallback com os mesmos parâmetros e tipo de retorno do método original, assim, quando a chamada original falhar o Hystrix irá disparar o fallback que retornará uma saudação padrão, desta forma o usuário não percebe que o comportamento da aplicação foi afetado.
@HystrixCommand(fallbackMethod = "getDefaultGreeting") public String getRandomGreeting() { String uri = "http://greeting-service" + greetingEndpointUri; String greeting = restTemplate.getForObject(uri, String.class); return greeting; } public String getDefaultGreeting() { return "Good bye"; }
Neste ponto, a aplicação já está pronta para utilizar os serviços básicos de Circuit Breaker oferecidos pelo Hystrix.
Para facilitar a visualização, criaremos um RestController com um endpoint que recebe um nome como parâmetro de url e exibe para o usuário uma saudação com o nome informado.
@RestController @RequestMapping("/hello") public class UserGreetingController { @Autowired private GreetingConsumer consumer; @GetMapping("/{username}") public String sayHello(@PathVariable String username) { String greeting = consumer.getRandomGreeting(); return greeting + " " + username + "!"; } }
Para verificar que a comunicação entre os serviços está funcionando adequadamente, é preciso executar a aplicação e acessar http://localhost:9090/hello/world. O comportamento esperado é obter as respostas: “Hi world!”, “Hello world!” ou “Hey world!”.
Para finalmente vermos o padrão Circuit Breaker agindo será preciso simular uma falha na comunicação, para isso pare a execução do serviço “
greeting-service”. Então tente acessar o endpoint http://localhost:9090/hello/world novamente, desta vez, a resposta será gerada pelo método de fallback, pois não foi possível acessar o serviço original, sendo assim a resposta obtida deve ser “Good bye world!”.
Conclusão
O padrão Circuit Breaker, como visto, é uma ótima ferramenta para lidar com falhas em sistemas distribuídos. No exemplo que realizamos se não houvesse a implementação de um fallback para a chamada, a aplicação gastaria tempo tentando acessar o serviço indisponível e depois retornaria um erro para o usuário, o que pode causar muito aborrecimento. Utilizando o Hystrix foi possível contornar a situação de falha de maneira elegante.
O código produzido está disponível neste repositório do GitHub na branch “hystrix”:
Consumer com Circuit Breaker
Não deixe de ler o próximo e último post da série que falará sobre Gateway Service com Spring Cloud Netflix utilizando Zuul para configurar rotas e filtros.
Para mais informações sobre o Hystrix consulte sua página da Wiki.