Resiliência utilizando Fallback e CircuitBreaker

Bruno Teofilo da Silva
OPANehtech

--

Com a consolidação do padrão de arquitetura de microsserviços, novos padrões de projeto estão surgindo e ganhando mais relevância na área de desenvolvimento de software.

Aqui nesse post irei abordar dois deles voltados a resiliência do serviço. Trata-se da capacidade do serviço continuar funcionando apesar de uma ou mais dependências estarem indisponíveis no momento.

O foco aqui é apresentar um problema desse tipo de arquitetura e formas diminuir o impacto dele. Não trarei aqui da implementação em si, focando apenas no design da solução. Desta forma, espero que não só desenvolvedores, mas pessoas com outros papéis do processo de desenvolvimento possam aproveitar a leitura.

Cenário

Temos um microsserviço de endereços, que ao receber o CEP, retorna as informações referentes ao CEP como resposta.

Esse nosso microsserviço, internamente, utiliza o sistema dos Correios para obter essas informações.

Fazendo um desenho do fluxo desse nosso microsserviço temos algo assim:

Enquanto estiver tudo bem com a comunicação entre o nosso microsserviço e o serviço dos Correios, tudo funciona sem problemas. Mas se por qualquer motivo, a comunicação apresentar uma falha, o nosso microsserviço para de funcionar. E é nesse ponto que entra o primeiro padrão que vamos abordar neste post.

Fallback

O Fallback é um plano b. Uma segunda opção não tão boa quanto a primeira, mas ainda assim aceitável.

Aplicando o conceito ao nosso microsserviço, caso o sistema dos correios apresente alguma falha, podemos por exemplo, usar uma base de dados local, que contêm os cadastros dos nossos clientes.

Essa opção pode apresentar alguns problemas, como por exemplo, o nome do logradouro está desatualizado. Mas ainda assim é uma opção melhor do que não ter informação nenhuma.

Então, atualizando a nossa implementação temos:

Destacado em vermelho no fluxo, temos o nosso Fallback (consultar a base de dados local), que será utilizado somente caso o consultar o sistema dos Correios não funcione.

Agora, digamos que a indisponibilidade do sistema dos Correios não seja ocasionada por uma falha, mas sim por uma manutenção programada. E que essa indisponibilidade irá durar algumas horas, ou até mesmo vários dias.

A cada solicitação de informações de CEP que o nosso microsserviço receber, iremos fazer a chamada para o sistema dos Correios, validar se houve sucesso ou falha, e após confirmar que ocorreu a falha desviar o fluxo para o nosso Fallback.

Justamente para este cenário, com o objetivo de evitar esse desperdício de tempo e recursos computacionais, que aplicamos o segundo padrão que irei abordar neste post.

CircuitBreaker

O CircuitBreaker é um disjuntor, ele serve para “abrir um circuito”, fazendo com que o fluxo de execução seja desviado para o Fallback antes da falha acontecer.

Para fazer isso, ele registra um histórico simplificado (status e/ou tempo de resposta, mas não o conteúdo) dos resultados das últimas execuções de um trecho do programa. E a cada execução avalia a saúde deste trecho

Ao avaliar que a saúde do trecho em questão está abaixo dos parâmetros definidos, o disjuntor cai, ou seja, o circuito fica aberto. Desviando a execução para o Fallback.

Após determinado intervalo de tempo ou número de execuções que foram desviadas, o circuito é alterado para o estado semiaberto, onde as execuções não sofrem esse desvio e passam a seguir o fluxo normal.

Desta forma avaliamos se a saúde do trecho já foi restaurada, para alterarmos o estado do circuito novamente, para fechado se a quantidade de falhas estiver dentro do limite, ou para aberto caso ainda esteja acima do limite.

Agora, aplicando no nosso cenário, digamos que é aceitável, na amostra das 100 últimas chamadas ao sistema dos Correios, até 5% de falhas. Enquanto 95% das solicitações ocorrerem com sucesso, o circuito permanece fechado e no máximo 5% das chamadas são desviadas para o Fallback.

Porém, se o sistema dos Correios está com alguma indisponibilidade, e todas, ou quase todas as chamadas apresentarem falha, nós podemos abrir o nosso circuito para desviar o fluxo para o Fallback, poupando tempo e recursos computacionais. Ao invés de fazer a chamada, aguardar a resposta, validar se houve sucesso ou falha para só então desviar o fluxo para o Fallback.

Mais uma vez, atualizando o fluxo do nosso microsserviço temos:

Destacado em verde no fluxo, temos os passos referentes a utilização do CircuitBreaker. Que se estiver aberto, irá desviar o fluxo direto para o nosso Fallback. Poupando tempo e recursos de computação para os casos de indisponibilidade do sistema do Correios.

Conclusão

Neste post, acompanhamos a evolução do nosso microsserviço para aumentar a tolerância a falhas utilizando o Fallback, que serve para responder a solicitação que recebemos, mesmo quando o sistema dos Correios apresentar alguma eventual falha.

Além disso, para os casos em que as falhas são constantes, vimos como utilizar o CircuitBreaker para poupar tempo e recursos desviando o fluxo para o Fallback antes mesmo de realizarmos a chamada para o sistema externo.

Referências

Caso tenha conseguido despertar o interesse no assunto, abaixo trago alguns links que utilizei para elaborar o texto deste post e nos quais você pode se aprofundar ainda mais.

· What are microservices?
https://microservices.io/

· Microservice Architecture pattern
https://microservices.io/patterns/microservices.html

Resilience4j
https://resilience4j.readme.io/

--

--

Bruno Teofilo da Silva
OPANehtech

Engenheiro de Software. Apaixonado por gatos, aficionado por tecnologia,entusiasta de robótica, aventureiro na culinária e gamer no tempo restante.