Compartilhar via


Padrão de interruptor de circuito

O padrão Circuit Breaker ajuda a lidar com falhas que podem levar diferentes períodos de tempo para serem resolvidas quando um aplicativo se conecta a um serviço ou recurso remoto. Um disjuntor bloqueia temporariamente o acesso a um serviço com falha depois de detectar falhas. Essa ação impede repetidas tentativas malsucedidas para que o sistema possa se recuperar efetivamente. Esse padrão pode melhorar a estabilidade e a resiliência de um aplicativo.

Contexto e problema

Em um ambiente distribuído, as chamadas para recursos e serviços remotos podem falhar devido a falhas transitórias. Falhas transitórias incluem recursos excessivamente comprometidos ou temporariamente indisponíveis, conexões de rede lentas ou tempos limite. Essas falhas normalmente se corrigem após um curto período de tempo. Para ajudar a gerenciar essas falhas, você deve criar um aplicativo de nuvem para usar uma estratégia, como o padrão de repetição.

Eventos imprevistos podem criar falhas que levam mais tempo para serem corrigidas. Essas falhas podem variar em gravidade, desde uma perda parcial de conectividade até uma falha de serviço completa. Nessas situações, um aplicativo não deve repetir continuamente uma operação que é improvável de ter êxito. Em vez disso, o aplicativo deve reconhecer rapidamente a operação com falha e lidar com a falha adequadamente.

Se um serviço estiver ocupado, a falha em uma parte do sistema poderá levar a falhas em cascata. Por exemplo, você pode configurar uma operação que invoca um serviço para implementar um tempo limite. Se o serviço não responder dentro desse período, a operação responderá com uma mensagem de falha.

No entanto, essa estratégia pode bloquear solicitações simultâneas para a mesma operação até que o período de tempo limite expire. Essas solicitações bloqueadas podem conter recursos críticos do sistema, como memória, threads e conexões de banco de dados. Esse problema pode esgotar recursos, o que pode falhar em outras partes não relacionadas do sistema que precisam usar os mesmos recursos.

Nessas situações, uma operação deve falhar imediatamente e apenas tentar invocar o serviço se for provável que ela tenha êxito. Para resolver esse problema, defina um tempo limite mais curto. Mas verifique se o tempo limite é longo o suficiente para que a operação seja bem-sucedida na maior parte do tempo.

Solução

O padrão disjuntor ajuda a impedir que um aplicativo tente executar repetidamente uma operação que provavelmente falhará. Esse padrão permite que o aplicativo continue em execução sem esperar que a falha seja corrigida ou desperdiçando ciclos de CPU ao determinar que a falha é persistente. O padrão disjuntor também permite que um aplicativo detecte quando a falha é resolvida. Se a falha for resolvida, o aplicativo poderá tentar invocar a operação novamente.

Observação

O Padrão Circuit Breaker serve a uma finalidade diferente do Padrão Retry. O padrão de repetição permite que um aplicativo repita uma operação com a expectativa de que ele eventualmente tenha êxito. O padrão disjuntor impede que um aplicativo execute uma operação que provavelmente falhará. Um aplicativo pode combinar esses dois padrões usando o padrão de Repetição para invocar uma operação por meio de um disjuntor. No entanto, a lógica de repetição deve ser sensível a quaisquer exceções retornadas pelo disjuntor e parar tentativas de repetição se o disjuntor indicar que uma falha não é transitória.

Um disjuntor atua como um proxy para operações que podem falhar. O proxy deve monitorar o número de falhas recentes e usar essas informações para decidir se deseja permitir que a operação prossiga ou retorne uma exceção imediatamente.

Você pode implementar o proxy como um computador de estado que inclui os estados a seguir. Esses estados imitam a funcionalidade de um disjuntor elétrico:

  • Fechado: A solicitação do aplicativo é roteada para a operação. O proxy mantém uma contagem do número de falhas recentes. Se a chamada para a operação não for bem-sucedida, o proxy incrementará essa contagem. Se o número de falhas recentes exceder um limite especificado em um determinado período de tempo, o proxy será colocado no estado Open e iniciará um temporizador de tempo limite. Quando o temporizador expira, o proxy é colocado no estado Half-Open .

    Observação

    Durante o tempo limite, o sistema tenta corrigir o problema que causou a falha antes de permitir que o aplicativo tente a operação novamente.

  • Abrir: A solicitação do aplicativo falha imediatamente e uma exceção é retornada ao aplicativo.

  • Estado Semiaberto: Um número limitado de solicitações do aplicativo pode atravessar e invocar a operação. Se essas solicitações forem bem-sucedidas, o disjuntor assumirá que a falha que causou a falha foi corrigida e o disjuntor alterna para o estado Fechado . O contador de falhas é reiniciado. Se qualquer solicitação falhar, o disjuntor assumirá que a falha ainda está presente, portanto, ela será revertida para o estado Abrir . Ele recomeça o cronômetro de tempo limite para que o sistema possa se recuperar da falha.

    Observação

    O estado Half-Open ajuda a impedir que um serviço de recuperação seja subitamente inundado com solicitações. À medida que um serviço se recupera, ele pode ser capaz de dar suporte a um volume limitado de solicitações até que a recuperação seja concluída. Mas enquanto a recuperação está em andamento, uma enxurrada de trabalho pode fazer com que o serviço expire ou falhe novamente.

O diagrama a seguir mostra as operações do contador para cada estado.

Diagrama que mostra os estados do disjuntor.

O contador de falha do estado Fechado é baseado em tempo. Ele é redefinido automaticamente em intervalos regulares. Esse design ajuda a impedir que o disjuntor entre no estado Abrir se ele tiver falhas ocasionais. O limite de falha dispara o estado Abrir somente quando um número especificado de falhas ocorre durante um intervalo especificado.

O contador de êxito para o estado Half-Open registra o número de tentativas bem-sucedidas de invocar a operação. O disjuntor é revertido para o estado Fechado após um número especificado de invocações de operação consecutivas bem-sucedidas. Se qualquer invocação falhar, o disjuntor entrará no estado Abrir imediatamente e o contador de êxito será redefinido na próxima vez que ele entrar no estado de Meio Aberto .

Observação

A recuperação do sistema é baseada em operações externas, como restaurar ou reiniciar um componente com falha ou reparar uma conexão de rede.

O padrão de disjuntor fornece estabilidade enquanto o sistema se recupera de uma falha e minimiza o impacto no desempenho. Ele pode ajudar a manter o tempo de resposta do sistema. Esse padrão rejeita rapidamente uma solicitação de uma operação que provavelmente falhará, em vez de aguardar o timeout da operação ou nunca retornar. Se o disjuntor gerar um evento sempre que mudar de estado, essas informações poderão ajudar a monitorar a integridade do componente do sistema protegido ou alertar um administrador quando um disjuntor mudar para o estado Aberto.

Você pode personalizar e adaptar esse padrão a diferentes tipos de falhas. Por exemplo, você pode aplicar um tempo limite de tempo limite crescente a um disjuntor. Você pode colocar o disjuntor no estado Aberto por alguns segundos inicialmente. Se a falha não for resolvida, aumente o tempo limite para alguns minutos e ajuste adequadamente. Em alguns casos, em vez de retornar uma falha e gerar uma exceção, o estado Abrir pode retornar um valor padrão que seja significativo para o aplicativo.

Observação

Tradicionalmente, os disjuntores dependiam de limites pré-configurados, como contagem de falhas e duração do tempo limite. Essa abordagem resultou em um comportamento determinístico, mas às vezes abaixo do ideal.

Técnicas adaptáveis que usam IA e machine learning podem ajustar dinamicamente limites com base em padrões de tráfego em tempo real, anomalias e taxas de falha histórica. Essa abordagem melhora a resiliência e a eficiência.

Problemas e considerações

Considere os seguintes fatores ao implementar esse padrão:

  • Tratamento de exceção: Um aplicativo que invoca uma operação por meio de um disjuntor deve ser capaz de lidar com as exceções se a operação não estiver disponível. O gerenciamento de exceções é baseado no aplicativo. Por exemplo, um aplicativo pode degradar temporariamente sua funcionalidade, invocar uma operação alternativa para tentar executar a mesma tarefa ou obter os mesmos dados ou relatar a exceção ao usuário e solicitar que ele tente novamente mais tarde.

  • Tipos de exceções: Os motivos de uma falha de solicitação podem variar em gravidade. Por exemplo, uma solicitação pode falhar porque um serviço remoto falha e requer vários minutos para ser recuperado ou porque um serviço sobrecarregado causa um tempo limite. Um disjuntor pode ser capaz de examinar os tipos de exceções que ocorrem e ajustar sua estratégia com base na natureza dessas exceções. Por exemplo, pode exigir um número maior de exceções de tempo limite para disparar o disjuntor para o estado Abrir em comparação com o número de falhas causadas pelo serviço indisponível.

  • Monitorização: Um disjuntor deve fornecer uma observabilidade clara em solicitações com falha e bem-sucedidas para que as equipes de operações possam avaliar a integridade do sistema. Use o rastreamento distribuído para visibilidade de ponta a ponta entre serviços.

  • Recuperabilidade: Você deve configurar o disjuntor para alinhar-se ao padrão de recuperação provável da operação que ele protege. Por exemplo, se o disjuntor permanecer no estado Aberto por um longo período, ele poderá gerar exceções mesmo se o motivo da falha for resolvido. Da mesma forma, um disjuntor pode flutuar e reduzir os tempos de resposta dos aplicativos se ele alternar do estado Open para o estado Semiaberto muito rapidamente.

  • Teste de operações com falha: No estado Abrir , em vez de usar um temporizador para determinar quando alternar para o estado de Meia-Abertura , um disjuntor pode executar ping periodicamente no serviço ou recurso remoto para determinar se ele está disponível. Esse ping pode tentar invocar uma operação com falha anterior ou usar uma operação especial de verificação de integridade fornecida pelo serviço remoto. Para obter mais informações, consulte Padrão de monitoramento de ponto de extremidade de integridade.

  • Substituição manual: Se o tempo de recuperação de uma operação com falha for extremamente variável, você deverá fornecer uma opção de ajuste manual que permite que um administrador feche um interruptor e redefina a contagem de falhas. Da mesma forma, um administrador pode forçar um disjuntor para o estado Aberto e reiniciar o tempo limite se a operação protegida estiver temporariamente indisponível.

  • Simultaneidade: Um grande número de instâncias simultâneas de um aplicativo pode acessar o mesmo disjuntor. A implementação não deve bloquear solicitações simultâneas nem adicionar uma sobrecarga excessiva a cada chamada a uma operação.

  • Diferenciação de recursos: Tenha cuidado ao usar um único disjuntor para um tipo de recurso se houver vários provedores independentes subjacentes. Por exemplo, em um repositório de dados que contém vários fragmentos, um fragmento pode estar totalmente acessível enquanto outro enfrenta um problema temporário. Se as respostas de erro nesses cenários forem mescladas, um aplicativo poderá tentar acessar alguns fragmentos mesmo quando a falha for provável. E o acesso a outros fragmentos pode ser bloqueado, mesmo que a chance de êxito seja alta.

  • Interrupção acelerada do circuito: Às vezes, uma resposta de falha pode conter informações suficientes para que o disjuntor desarme imediatamente e permaneça desarmado por um período mínimo de tempo. Por exemplo, a resposta de erro de um recurso compartilhado sobrecarregado pode indicar que o aplicativo deve tentar novamente em alguns minutos, em vez de tentar novamente imediatamente.

  • Implantações de várias regiões: Você pode criar um disjuntor para implantações de região única ou de várias regiões. Para projetar implantações de várias regiões, use balanceadores de carga globais ou estratégias personalizadas de quebra de circuito com reconhecimento de região que ajudam a garantir failover controlado, otimização de latência e conformidade regulatória.

  • Disjuntores de malha de serviço: Você pode implementar disjuntores na camada de aplicação ou como um recurso transversal e abstrato. Por exemplo, as malhas de serviço geralmente dão suporte à quebra de circuito como um sidecar ou como uma funcionalidade autônoma sem modificar o código do aplicativo.

    Observação

    Um serviço poderá retornar HTTP 429 (muitas solicitações) se estiver limitando o cliente ou HTTP 503 (serviço indisponível) se o serviço não estiver disponível. A resposta pode incluir outras informações, como a duração prevista do atraso.

  • Reprodução de solicitação com falha: No estado Aberto, em vez de simplesmente falhar rapidamente, um disjuntor também pode registrar os detalhes de cada solicitação em um registro e organizar para que essas solicitações sejam reproduzidas quando o recurso ou serviço remoto estiver disponível.

  • Tempos limite inadequados em serviços externos: Um disjuntor pode não proteger totalmente os aplicativos contra falhas em serviços externos que têm longos períodos de tempo limite. Se o tempo limite for excessivamente longo, uma thread que executa um disjuntor poderá ficar bloqueada por um período prolongado antes que o disjuntor indique que a operação falhou. Durante esse tempo, muitas outras instâncias de aplicativo também podem tentar invocar o serviço por meio do disjuntor e amarrar vários threads antes que todos falhem.

  • Adaptabilidade à diversificação de computação: Os disjuntores devem considerar diferentes ambientes de computação, desde cargas de trabalho sem servidor até cargas de trabalho em contêineres, em que fatores como inícios a frio e escalabilidade afetam o tratamento de falhas. Abordagens adaptáveis podem ajustar dinamicamente estratégias com base no tipo de computação, o que ajuda a garantir a resiliência entre arquiteturas heterogêneas.

Quando usar esse padrão

Use esse padrão quando:

  • Você deseja evitar falhas em cascata interrompendo chamadas de serviço remoto excessivas ou solicitações de acesso a um recurso compartilhado se essas operações provavelmente falharem.

  • Você deseja rotear o tráfego de forma inteligente com base em sinais de falha em tempo real para aprimorar a resiliência de várias regiões.

  • Você deseja proteger contra dependências lentas para que você possa manter seus objetivos de nível de serviço e evitar degradação de desempenho de serviços de alta latência.

  • Você deseja gerenciar problemas de conectividade intermitente e reduzir falhas de solicitação em ambientes distribuídos.

O padrão pode não ser adequado nestes casos:

  • Você precisa gerenciar o acesso a recursos privados locais em um aplicativo, como estruturas de dados na memória. Nesse ambiente, um disjuntor adiciona sobrecarga ao seu sistema.

  • Você precisa usá-lo como um substituto para lidar com exceções na lógica de negócios de seus aplicativos.

  • Algoritmos de repetição conhecidos são suficientes e suas dependências são projetadas para lidar com mecanismos de repetição. Nesse cenário, um disjuntor em seu aplicativo pode adicionar complexidade desnecessária ao seu sistema.

  • Esperar que um disjuntor seja redefinido pode introduzir atrasos inaceitáveis.

  • Você tem uma arquitetura orientada por mensagens ou orientada por eventos, pois elas geralmente roteiam mensagens com falha para uma fila de mensagens mortas para processamento manual ou adiado. Mecanismos internos de isolamento e repetição de falhas geralmente são suficientes.

  • A recuperação de falha é gerenciada no nível da infraestrutura ou da plataforma, como com verificações de integridade em balanceadores de carga globais ou malhas de serviço.

Design de carga de trabalho

Avalie como usar o padrão Circuit Breaker no design de uma arquitetura de carga de trabalho para atender às metas e princípios abordados nos pilares do Azure Well-Architected Framework. A tabela a seguir fornece diretrizes sobre como esse padrão dá suporte às metas de cada pilar.

Pilar Como esse padrão apoia os objetivos do pilar
As decisões de design de confiabilidade ajudam sua carga de trabalho a se tornar resiliente ao mau funcionamento e garantir que ela se recupere para um estado totalmente funcional após a ocorrência de uma falha. Esse padrão ajuda a impedir que uma dependência com falha sobrecarregue. Use este padrão para acionar degradação suave na carga de trabalho. Disjuntores de casal com recuperação automática para fornecer autopreservação e auto-cura.

- RE:03 Análise do modo de falha
- Falhas transitórias
- RE:07 Autopreservação
A Eficiência de Desempenho ajuda sua carga de trabalho a atender com eficiência às demandas por meio de otimizações no dimensionamento, nos dados e no código. Esse padrão evita a abordagem de tentar novamente em caso de erro, que pode levar ao uso excessivo de recursos durante a recuperação de uma dependência e pode sobrecarregar o desempenho em uma dependência que está tentando passar por recuperação.

- PE:07 Código e infraestrutura
- PE:11 Respostas a problemas em tempo real

Se esse padrão introduzir compensações dentro de um pilar, considere-as em relação aos objetivos dos outros pilares.

Exemplo

Este exemplo implementa o padrão Circuit Breaker para ajudar a evitar o excesso de cota usando a camada gratuita vitalícia do Azure Cosmos DB. Essa camada é principalmente para dados não críticos e opera sob um plano de capacidade que aloca uma cota específica de unidades de recursos por segundo. durante eventos sazonais, a demanda pode exceder a capacidade fornecida, o que pode resultar em respostas 429.

Quando ocorrem picos de demanda, os alertas do Azure Monitor com limites dinâmicos detectam e notificam proativamente as operações e as equipes de gerenciamento de que o banco de dados requer mais capacidade. Simultaneamente, um disjuntor ajustado usando padrões de erro históricos é usado para evitar falhas em cascata. Nesse estado, o aplicativo se degrada de forma controlada, retornando respostas padrão ou em cache. O aplicativo informa aos usuários sobre a indisponibilidade temporária de determinados dados, preservando a estabilidade geral do sistema.

Essa estratégia aprimora a resiliência que se alinha à justificativa empresarial. Ele controla os aumentos de capacidade para que as equipes de carga de trabalho possam gerenciar aumentos de custos deliberadamente e manter a qualidade do serviço sem aumentar inesperadamente as despesas operacionais. Depois que a demanda diminuir ou a maior capacidade for confirmada, o disjuntor é reiniciado e o aplicativo retornará à funcionalidade completa que se alinha aos objetivos técnicos e orçamentários.

Diagrama que mostra o Azure Cosmos DB e uma implementação de disjuntor no Serviço de Aplicativo do Azure.

O diagrama tem três seções primárias. A primeira seção contém dois ícones do navegador da Web. O primeiro ícone exibe uma interface do usuário totalmente funcional e o segundo ícone mostra uma experiência de usuário degradada que tem um aviso na tela para indicar o problema para os usuários. A segunda seção é colocada em um retângulo de linha tracejada, que é dividido em dois grupos. O grupo superior inclui os recursos de carga de trabalho, o Serviço de Aplicativo e o Azure Cosmos DB. Setas de ambos os ícones do navegador da Web apontam para a instância do Serviço de Aplicativo, representando solicitações de entrada do cliente. Além disso, as setas da instância do Serviço de Aplicativo apontam para o Azure Cosmos DB, que indicam interações de dados entre os serviços de aplicativo e o banco de dados. Outra seta faz um ciclo na instância do App Service, voltando para si mesma, simbolizando o mecanismo de tempo de espera do disjuntor. Esse loop significa que, quando uma resposta de 429 Solicitações Demais é detectada, o sistema volta a atender respostas armazenadas em cache, degradando a experiência do usuário até que a situação seja resolvida. O grupo inferior desta seção se concentra na observabilidade e alertas. O Azure Monitor coleta dados dos recursos do Azure no grupo superior. O Azure Monitor também se conecta a um ícone de regra de alerta. A terceira seção mostra o fluxo de trabalho de escalabilidade disparado quando o alerta é acionado. Uma seta conecta o ícone de alerta aos aprovadores, o que indica que a notificação é enviada a eles para revisão. Outra seta conduz os aprovadores a um console de desenvolvimento, indicando o processo de aprovação para dimensionar o banco de dados. Por fim, uma seta subsequente se estende do console de desenvolvimento para o Azure Cosmos DB, que ilustra a ação de dimensionar o banco de dados em resposta à condição de sobrecarga.

Baixe um arquivo do Visio dessa arquitetura.

Fluxo A: Estado fechado

  • O sistema opera normalmente e todas as solicitações chegam ao banco de dados sem retornar respostas 429 HTTP.

  • O disjuntor permanece fechado e nenhuma resposta padrão ou armazenada em cache é necessária.

Fluxo B: Estado aberto

  1. Quando o disjuntor recebe a primeira 429 resposta, ele viaja para um estado Open .

  2. As solicitações subsequentes são imediatamente interrompidas, o que retorna respostas padrões ou em cache e informa os usuários da degradação temporária. O aplicativo é protegido contra sobrecarga adicional.

  3. O Azure Monitor recebe logs e dados de telemetria e os avalia em relação aos limites dinâmicos. Um alerta é disparado se as condições da regra de alerta forem atendidas.

  4. Um grupo de ações notifica proativamente a equipe de operações da condição de sobrecarga.

  5. Após a aprovação da equipe de gestão de carga de trabalho, a equipe de operações poderá aumentar a taxa de transferência provisionada, para aliviar a sobrecarga, ou atrasar o dimensionamento, caso a carga diminua naturalmente.

Fluxo C: estado Half-Open

  1. Após um tempo limite predefinido, o disjuntor entra em um estado de Meio Aberto que permite um número limitado de solicitações de avaliação.

  2. Se essas solicitações de avaliação 429 forem bem-sucedidas sem retornar respostas, o disjuntor será redefinido para um estado Fechado e as operações normais voltarão ao Fluxo A. Se as falhas persistirem, o disjuntor será revertido para o estado Aberto ou o Fluxo B.

Componentes

  • O Serviço de Aplicativo do Azure hospeda o aplicativo Web que serve como o ponto de entrada principal para solicitações de cliente. O código do aplicativo implementa a lógica que impõe políticas de disjuntor e fornece respostas padrão ou armazenadas em cache quando o circuito está aberto. Essa arquitetura ajuda a evitar sobrecarga em sistemas downstream e manter a experiência do usuário durante o pico de demanda ou falhas.

  • do Azure Cosmos DB é um dos armazenamentos de dados do aplicativo. Ele fornece dados não críticos por meio da camada gratuita, que é ideal para pequenas cargas de trabalho de produção. O mecanismo de disjuntor ajuda a limitar o tráfego para o banco de dados durante períodos de alta demanda.

  • O Azure Monitor funciona como a solução de monitoramento centralizada. Ele agrega todos os logs de atividades para ajudar a garantir uma observabilidade abrangente de ponta a ponta. O Azure Monitor recebe logs e dados de telemetria do Serviço de Aplicativo e das principais métricas do Azure Cosmos DB (como o número de 429 respostas) para agregação e análise.

  • alertas do Azure Monitor pesar regras de alerta em relação limites dinâmicos para identificar possíveis interrupções com base em dados históricos. Alertas predefinidos notificam a equipe de operações quando os limites são violados.

    Às vezes, a equipe de carga de trabalho pode aprovar um aumento na taxa de transferência provisionada, mas a equipe de operações prevê que o sistema pode se recuperar por conta própria porque a carga não é muito alta. Nesses casos, o tempo limite do disjuntor expira naturalmente. Durante esse tempo, se as respostas 429 cessarem, o cálculo de limite detectará as interrupções prolongadas e as excluirá do algoritmo de aprendizado. Como resultado, na próxima vez que ocorrer uma sobrecarga, o limite aguardará uma taxa de erro mais alta no Azure Cosmos DB, o que atrasa a notificação. Esse ajuste permite que o disjuntor lide com o problema sem um alerta imediato, o que melhora o custo e a eficiência operacional.

  • O padrão de Aplicativo Web Confiável aplica o padrão de Disjuntor a aplicativos Web que convergem na nuvem.

  • O padrão de repetição descreve como um aplicativo pode lidar com falhas temporárias previstas quando tenta se conectar a um serviço ou recurso de rede repetindo de forma transparente uma operação que falhou anteriormente.

  • O Padrão de Monitoramento de Integridade no Endpoint descreve como um circuit breaker pode testar a integridade de um serviço enviando uma solicitação para um endpoint que o serviço expõe. O serviço deve retornar informações que indiquem seu status.