Padrão de disjuntor - AWS Orientação prescritiva

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Padrão de disjuntor

Intenção

O padrão do disjuntor pode impedir que um serviço de chamada repita uma chamada para outro serviço (chamador) quando a chamada já causou repetidos tempos limite ou falhas. O padrão também é usado para detectar quando o serviço do receptor está funcionando novamente.

Motivação

Quando vários microsserviços colaboram para lidar com solicitações, um ou mais serviços podem ficar indisponíveis ou apresentar alta latência. Quando aplicativos complexos usam microsserviços, uma interrupção em um microsserviço pode levar à falha do aplicativo. Os microsserviços se comunicam por meio de chamadas de procedimentos remotos, e erros transitórios podem ocorrer na conectividade da rede, causando falhas. (Os erros transitórios podem ser tratados usando o padrão de repetição com recuo.) Durante a execução síncrona, a cascata de tempos limite ou falhas pode causar uma experiência ruim para o usuário.

No entanto, em algumas situações, as falhas podem levar mais tempo para serem resolvidas, por exemplo, quando o serviço do destinatário está inativo ou uma contenção no banco de dados resulta em tempos limite. Nesses casos, se o serviço de chamada repetir as chamadas repetidamente, essas novas tentativas poderão resultar em contenção na rede e no consumo do pool de threads do banco de dados. Além disso, se vários usuários repetirem o aplicativo repetidamente, isso piorará o problema e poderá causar degradação do desempenho de todo o aplicativo.

O padrão do disjuntor foi popularizado por Michael Nygard em seu livro Release It (Nygard 2018). Esse padrão de design pode impedir que um serviço de chamada repita uma chamada de serviço que já tenha causado repetidos tempos limite ou falhas. Ele também pode detectar quando o serviço do chamador está funcionando novamente.

Os objetos do disjuntor funcionam como disjuntores elétricos que interrompem automaticamente a corrente quando há uma anormalidade no circuito. Os disjuntores elétricos desligam ou desligam o fluxo da corrente quando há uma falha. Da mesma forma, o objeto do disjuntor está situado entre o chamador e o serviço do chamador e dispara se o chamador não estiver disponível.

As falácias da computação distribuída são um conjunto de afirmações feitas por Peter Deutsch e outros da Sun Microsystems. Eles dizem que programadores iniciantes em aplicativos distribuídos invariavelmente fazem suposições falsas. A confiabilidade da rede, as expectativas de latência zero e as limitações de largura de banda resultam em aplicativos de software escritos com o mínimo de tratamento de erros de rede.

Durante uma interrupção na rede, os aplicativos podem esperar por uma resposta indefinidamente e consumir continuamente os recursos do aplicativo. Deixar de repetir as operações quando a rede estiver disponível também pode levar à degradação do aplicativo. Se as chamadas de API para um banco de dados ou um serviço externo expirarem devido a problemas de rede, chamadas repetidas sem disjuntor podem afetar o custo e o desempenho.

Aplicabilidade

Use esse padrão quando:

  • O serviço de chamadas faz uma chamada que provavelmente falhará.

  • A alta latência exibida pelo serviço do destinatário (por exemplo, quando as conexões do banco de dados são lentas) causa tempos limite no serviço do destinatário.

  • O serviço do chamador faz uma chamada síncrona, mas o serviço do chamador não está disponível ou apresenta alta latência.

Problemas e considerações

  • Implementação independente de serviço: para evitar o excesso de código, recomendamos que você implemente o objeto disjuntor de forma independente de microsserviços e orientada por API.

  • Fechamento do circuito pelo chamador: Quando o chamador se recupera de um problema ou falha de desempenho, ele pode atualizar o status do circuito para. CLOSED Essa é uma extensão do padrão do disjuntor e pode ser implementada se seu objetivo de tempo de recuperação (RTO) exigir.

  • Chamadas multiencadeadas: o valor do tempo limite de expiração é definido como o período de tempo em que o circuito permanece desligado antes que as chamadas sejam roteadas novamente para verificar a disponibilidade do serviço. Quando o serviço do destinatário é chamado em vários segmentos, a primeira chamada que falhou define o valor do tempo limite de expiração. Sua implementação deve garantir que as chamadas subsequentes não alterem o tempo limite de expiração indefinidamente.

  • Forçar a abertura ou o fechamento do circuito: os administradores do sistema devem ter a capacidade de abrir ou fechar um circuito. Isso pode ser feito atualizando o valor do tempo limite de expiração na tabela do banco de dados.

  • Observabilidade: O aplicativo deve ter o registro configurado para identificar as chamadas que falham quando o disjuntor está aberto.

Implementação

Arquitetura de alto nível

No exemplo a seguir, o chamador é o serviço de pedidos e o destinatário é o serviço de pagamento.

Quando não há falhas, o serviço de pedidos encaminha todas as chamadas para o serviço de pagamento pelo disjuntor, conforme mostra o diagrama a seguir.

Padrão de disjuntor sem falhas.

Se o serviço de pagamento expirar, o disjuntor poderá detectar o tempo limite e rastrear a falha.

Disjuntor com falha no serviço de pagamento.

Se os tempos limite excederem um limite especificado, o aplicativo abrirá o circuito. Quando o circuito está aberto, o objeto do disjuntor não encaminha as chamadas para o serviço de pagamento. Ele retorna uma falha imediata quando o serviço de pedidos liga para o serviço de pagamento.

O disjuntor interrompe o encaminhamento para o serviço de pagamento.

O objeto do disjuntor tenta periodicamente verificar se as chamadas para o serviço de pagamento foram bem-sucedidas.

O disjuntor repete periodicamente o serviço de pagamento.

Quando a chamada para o serviço de pagamento é bem-sucedida, o circuito é fechado e todas as chamadas adicionais são encaminhadas para o serviço de pagamento novamente.

Disjuntor com serviço de pagamento em funcionamento.

Implementação usando serviços AWS

A solução de amostra usa fluxos de trabalho expressos AWS Step Functionspara implementar o padrão do disjuntor. A máquina de estado Step Functions permite configurar os recursos de repetição e o fluxo de controle baseado em decisão necessários para a implementação do padrão.

A solução também usa uma tabela do Amazon DynamoDB como armazenamento de dados para rastrear o status do circuito. Isso pode ser substituído por um armazenamento de dados na memória, como o Amazon ElastiCache for Redis, para melhorar o desempenho.

Quando um serviço deseja chamar outro serviço, ele inicia o fluxo de trabalho com o nome do serviço do destinatário. O fluxo de trabalho obtém o status do disjuntor na tabela do CircuitStatus DynamoDB, que armazena os serviços atualmente degradados. Se CircuitStatus contiver um registro não expirado do receptor, o circuito está aberto. O fluxo de trabalho do Step Functions retorna uma falha imediata e sai com um FAIL estado.

Se a CircuitStatus tabela não contiver um registro para o destinatário ou contiver um registro expirado, o serviço estará operacional. A ExecuteLambda etapa na definição da máquina de estado chama a função Lambda que é enviada por meio de um valor de parâmetro. Se a chamada for bem-sucedida, o fluxo de trabalho do Step Functions sairá com um SUCCESS estado.

Implementação do disjuntor com o AWS Step Functions DynamoDB.

Se a chamada de serviço falhar ou ocorrer um tempo limite, o aplicativo tentará novamente com um recuo exponencial por um número definido de vezes. Se a chamada de serviço falhar após as novas tentativas, o fluxo de trabalho insere um registro na CircuitStatus tabela do serviço com o anExpiryTimeStamp, e o fluxo de trabalho sai com um estado. FAIL As chamadas subsequentes para o mesmo serviço retornam uma falha imediata, desde que o disjuntor esteja aberto. A Get Circuit Status etapa na definição da máquina de estado verifica a disponibilidade do serviço com base no ExpiryTimeStamp valor. Os itens expirados são excluídos da CircuitStatus tabela usando o recurso de tempo de vida (TTL) do DynamoDB.

Código de exemplo

O código a seguir usa a função GetCircuitStatus Lambda para verificar o status do disjuntor.

var serviceDetails = _dbContext.QueryAsync<CircuitBreaker>(serviceName, QueryOperator.GreaterThan, new List<object> {currentTimeStamp}).GetRemainingAsync(); if (serviceDetails.Result.Count > 0) { functionData.CircuitStatus = serviceDetails.Result[0].CircuitStatus; } else { functionData.CircuitStatus = ""; }

O código a seguir mostra as declarações da Amazon States Language no fluxo de trabalho Step Functions.

"Is Circuit Closed": { "Type": "Choice", "Choices": [ { "Variable": "$.CircuitStatus", "StringEquals": "OPEN", "Next": "Circuit Open" }, { "Variable": "$.CircuitStatus", "StringEquals": "", "Next": "Execute Lambda" } ] }, "Circuit Open": { "Type": "Fail" }

GitHub repositório

Para obter uma implementação completa da arquitetura de amostra desse padrão, consulte o GitHub repositório em https://github.com/aws-samples/ circuit-breaker-netcore-blog.

Referências do blog

Conteúdo relacionado