Microsserviços: como obter mais resiliência

Uma das principais vantagens da arquitetura de microsserviços é a sua maior capacidade de resiliência.

A ideia por trás dessa resiliência é simples: se dividirmos as aplicações monolíticas em partes menores e autônomas, podemos isolar as falhas (em redes, componentes, recursos de computação, etc) e resistir à elas sem que todo o sistema seja afetado.

Mas essa arquitetura gera um desafio: gerenciar uma grande suíte de serviços.

Diferentemente da arquitetura monolítica, em que uma só grande aplicação precisa ser monitorada, na de microsserviços temos dezenas ou centenas de serviços e elementos separados.

Por isso, é necessário usar mecanismos que auxiliem no monitoramento para tornar os microsserviços mais resilientes e manter a capacidade de computação e a consistência dos dados.

A seguir, mostraremos as quatro principais formas de obter mais resiliência:

1. Implementando um Health Endpoint

Às vezes, instâncias de serviço ficam incapazes de manipular solicitações, mesmo ainda estando em execução.

Um Health Endpoint oferece um monitoramento avançado da integridade dos microsserviços, que ajuda a entender o desempenho geral do sistema e detectar pontos de falha como esse.

Ele faz verificações como:

  • Status do banco de dados;
  • Status do cache;
  • Status do servidor host;
  • Dependências de outros microsserviços.

Com essas informações, é possível ter uma visão realista da integridade. Elas são entregues por meio de um aplicativo monitor, que monitora os dados, os agrega e os apresenta em um painel.

Ao implementar o Health Endpoint, é preciso planejar que informações precisam ser coletadas e como devem ser apresentadas. Além disso, é necessário categorizar os alertas em ‘crítico’, ‘alta prioridade’ e ‘baixa prioridade’, por exemplo.

2. Implementando o padrão Retry

Essa uma estratégia de repetição de requisição.

As aplicações geralmente são dependentes de APIs, serviços de back-end e bancos de dados, por exemplo. Quando um problema de natureza transitória (temporal) ocorre, a solicitação falha ou a aplicação atinge o tempo limite e se torna instável após alguns segundos.

O padrão Retry resolve esse problema, ao tentar realizar a operação novamente em horários configurados. É importante haver um backoff para aumentar continuamente o tempo entre novas tentativas e o efeito cascata ser reduzido.

Existem várias estratégias de Retry que podem ser utilizadas, como:

  • Intervalo exponencial: tentar novamente em prazos progressivamente mais longos;
  • Intervalo fixo: tentar novamente em intervalos pré-definidos (é preciso ter cuidado ao fixar intervalos curtos e um número de tentativas elevado, pois isso pode ser interpretado como um DoS Attack);
  • Intervalo aleatório: tentar novamente em intervalos aleatórios.

3. Implementando o padrão Circuit Breaker

Diferentemente do padrão Retry, o Circuit Breaker impede a execução de operações de solicitação que provavelmente falharão (porque outros serviços estão indisponíveis ou exibem latências altas, por exemplo).

Isso impede que o serviço passe muito tempo aguardando a resposta de outro, algo que pode causar um efeito cascasta e levar ao esgotamento de recursos.

Quando o número de falhas ultrapassa um determinado limite, e Circuit Breaker entra em ação. Depois disso, todas as tentativas de execução de operações falharão durante o período de tempo limite.

Quando esse tempo limite expirar, o Circuit Breaker permitirá que um determinado número de solicitações de teste passe. Se elas forem bem sucedidas, o Circuit Breaker voltará ao normal. Caso contrário, o período de tempo limite será reiniciado.

Esse padrão normalmente é utilizado juntamente com o Retry, e pode ser implantado com base na porcentagem de solicitações com falha, no número de falhas ou no tipo de erro.

4. Implementando o padrão Bulkhead

O termo ‘Bulkhead’ refere-se à estrutura que é usada em embarcações para criar partições no casco. Caso haja uma abertura, essas partições impedem que a água preencha todo o casco e afunde a embarcação.

Com o padrão Bulkhead, é possível isolar diferentes partes da aplicação, de modo que, caso algum serviço falhe, os outros não sejam afetados.

Se uma aplicação utiliza três componentes diferentes (A, B e C), e um deles vier a travar, todos os pedidos serão paralisados à espera de uma resposta dele. O padrão Bulkhead impede que isso aconteça.

Ao implementá-lo, é preciso colocar as partições em locais estratégicos.

Essas são as principais formas de tornar microsserviços mais resilientes, que permitem que seus usuários usufruam ainda mais de suas vantagens, como maior liberdade de desenvolvimento e redução de custos.