Processe falhas que possam demorar um período de tempo de recuperação variável ao ligar a um serviço ou recurso remoto. 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, como conexões de rede lentas, tempos limite ou recursos comprometidos em excesso ou temporariamente indisponíveis. Estas falhas costumam ser corrigidas de forma autónoma após um breve período de tempo, e uma aplicação na cloud robusta deve ser preparada para processá-las através de uma estratégia como o Padrão de repetição.
No entanto, pode também haver situações em que as falhas se devem a eventos imprevistos e podem demorar muito mais tempo a corrigir. Estas falhas podem variar em termos de gravidade, de uma perda parcial de conectividade à falha total de um serviço. Nessas situações, pode ser inútil para um aplicativo repetir continuamente uma operação que provavelmente não terá êxito e, em vez disso, o aplicativo deve aceitar rapidamente que a operação falhou e lidar com essa falha de acordo.
Adicionalmente, se um serviço estiver muito ocupado, a falha numa parte de um sistema poderá gerar falhas em cascata. Por exemplo, uma operação que invoca um serviço pode ser configurada para implementar um tempo limite e responder com uma mensagem de falha se o serviço não responder dentro desse período. No entanto, essa estratégia pode fazer com que muitas solicitações simultâneas para a mesma operação sejam bloqueadas até que o período de tempo limite expire. Estes pedidos bloqueados poderão conter recursos de sistema cruciais, como memória, threads, ligações de base de dados, etc. Assim, esses recursos podem se esgotar, causando falha de outras partes possivelmente não relacionadas do sistema que precisam usar os mesmos recursos. Nestas situações, é preferível que a operação falhe imediatamente e tente apenas invocar o serviço se tiver boas probabilidades de sucesso. Definir um tempo limite mais curto pode ajudar a resolver esse problema, mas o tempo limite não deve ser tão curto que a operação falhe na maioria das vezes, mesmo que a solicitação ao serviço acabe sendo bem-sucedida.
Solução
O padrão de disjuntor pode impedir que um aplicativo tente executar repetidamente uma operação que provavelmente falhará. Permitir que esta continue sem esperar que a falha seja corrigida ou desperdiçar ciclos de CPU enquanto determina que a falha é duradoura. O padrão do Disjuntor Automático também permite que uma aplicação detete se a falha foi resolvida. Se o problema aparentar estar resolvido, a aplicação pode tentar invocar a operação.
O objetivo do padrão do Disjuntor Automático é diferente do Padrão de repetição. O Padrão de repetição permite a uma aplicação repetir uma operação com a expectativa de que esta seja bem-sucedida. O padrão do Disjuntor Automático impede que uma aplicação efetue uma operação que é provável que falhe. Uma aplicação pode combinar estes dois padrões ao utilizar o padrão de Repetição para invocar uma operação através de um disjuntor automático. No entanto, a lógica de repetição deve ser sensível a eventuais exceções devolvidas pelo disjuntor automático e abandonar tentativas de repetição se o disjuntor automático indicar que uma falha não é transitória.
Um disjuntor automático atua como proxy para operações suscetíveis de falhar. O proxy deve monitorar o número de falhas recentes que ocorreram e usar essas informações para decidir se permite que a operação prossiga ou retorna uma exceção imediatamente.
O proxy pode ser implementado como computador com estado, tendo os seguintes estados que emulam a funcionalidade de um disjuntor automático elétrico:
Fechado: o pedido da aplicação é encaminhado para a operação. O proxy mantém uma contagem do número de falhas recentes e, se a chamada para a operação não for bem-sucedida, o proxy aumenta esta contagem. Se o número de falhas recentes exceder um limiar especificado num determinado período de tempo, o proxy é colocado em estado Aberto. Neste ponto, o proxy inicia um temporizador de tempo limite e, quando esse temporizador expira, o proxy é colocado no estado Semiaberto.
O objetivo do temporizador de tempo limite é dar ao sistema tempo para corrigir o problema que causou a falha antes de permitir que o aplicativo tente executar a operação novamente.
Aberto: o pedido da aplicação falha imediatamente e uma exceção é devolvida à aplicação.
Meio-aberto: um número limitado de pedidos da aplicação pode passar e invocar a operação. Se estes pedidos forem bem-sucedidos, assume-se que a falha que estava a causar o problema foi corrigida e o disjuntor automático muda para o estado Fechado (a contagem de falhas é reposta). Se alguma solicitação falhar, o disjuntor assume que a falha ainda está presente para que ele reverta para o estado Open e reinicie o temporizador de tempo limite para dar ao sistema um período adicional de tempo para se recuperar da falha.
O estado Meio-Aberto é útil para impedir um serviço de recuperação de ficar repentinamente sobrecarregado com pedidos. À medida que um serviço se recupera, ele pode ser capaz de suportar 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 atinja o tempo limite ou falhe novamente.
Na figura, o contador de falhas utilizado pelo estado Fechado é baseado em tempo. É automaticamente reiniciado em intervalos periódicos. Este design ajuda a evitar que o disjuntor entre no estado Open se ocorrer falhas ocasionais. O limiar de falha que coloca o disjuntor automático em estado Aberto só é alcançado após um número especificado de falhas ter ocorrido durante um intervalo especificado. O contador utilizado pelo estado Meio-Aberto regista o número de tentativas bem-sucedidas de invocar a operação. O disjuntor automático regressa ao estado Fechado após um número especificado de invocações de operação consecutivas ter sito efetuado com êxito. Se alguma invocação falhar, o disjuntor automático entra imediatamente no estado Aberto e a contagem de tentativas bem-sucedidas é reposta da próxima vez que entrar no estado Meio-Aberto.
A forma como o sistema recupera é processada de forma externa, possivelmente ao restaurar ou reiniciar um componente falhado ou ao reparar uma ligação de rede.
O padrão do Disjuntor Automático confere estabilidade enquanto o sistema recupera de uma falha e minimiza o impacto no desempenho. Pode ajudar a manter o tempo de resposta do sistema ao rejeitar rapidamente um pedido de uma operação com boas probabilidades de falhar, em vez de esperar que o limite de tempo de uma operação seja ultrapassado ou que esta nunca seja devolvida. Se o disjuntor automático gerar um evento sempre que muda de estado, esta informação pode ser utilizada para monitorizar o estado de funcionamento da parte do sistema protegida pelo disjuntor automático ou para alertar um administrador quando um disjuntor automático passar para o estado Aberto.
O padrão é personalizável e pode ser adaptado segundo o tipo da possível falha. Por exemplo, você pode aplicar um temporizador de tempo limite crescente a um disjuntor. Você pode colocar o disjuntor no estado Abrir por alguns segundos inicialmente e, se a falha não tiver sido resolvida, aumentar o tempo limite para alguns minutos e assim por diante. Em alguns casos, em vez de o estado Aberto devolver uma falha e gerar uma exceção, poderá ser útil regressar a um valor predefinido que seja significativo para a aplicação.
Nota
Tradicionalmente, os disjuntores dependiam de limites pré-configurados, como contagem de falhas e duração do tempo limite, resultando em um comportamento determinístico, mas às vezes subótimo. No entanto, técnicas adaptativas usando IA e ML podem ajustar dinamicamente os limites com base em padrões de tráfego em tempo real, anomalias e taxas de falha históricas, tornando o disjuntor mais resiliente e eficiente.
Problemas e considerações
Deve considerar os seguintes pontos ao decidir como implementar este padrão:
Tratamento de exceções: Um aplicativo que invoca uma operação através de um disjuntor deve estar preparado para lidar com as exceções levantadas se a operação não estiver disponível. A forma como as exceções são processadas depende da aplicação. Por exemplo, uma aplicação pode degradar temporariamente o funcionamento da mesma, invocar uma operação alternativa para tentar efetuar a mesma tarefa, obter os mesmos dados ou reportar a exceção ao utilizador e pedir a este que tente novamente mais tarde.
Tipos de exceções: Uma solicitação pode falhar por muitos motivos, alguns dos quais podem indicar um tipo mais grave de falha do que outros. Por exemplo, uma solicitação pode falhar porque um serviço remoto falhou e levará vários minutos para se recuperar, ou devido a um tempo limite devido ao serviço estar temporariamente sobrecarregado. Um disjuntor automático poderá conseguir examinar os tipos de exceções que ocorrem e ajustar a respetiva estratégia consoante a natureza dessas exceções. Por exemplo, pode ser necessário um número maior de exceções de tempo limite para levar o disjuntor ao estado Open em comparação com o número de falhas devido ao serviço estar completamente indisponível.
de monitoramento: Um disjuntor deve fornecer observabilidade clara em solicitações fracassadas e bem-sucedidas, permitindo que as equipes de operações avaliem a integridade do sistema. Use o rastreamento distribuído para visibilidade de ponta a ponta entre serviços.
de capacidade de recuperação: Você deve configurar o disjuntor para corresponder ao provável padrão de recuperação da operação que ele está protegendo. Por exemplo, se o disjuntor automático permanecer muito tempo no estado Aberto, poderá colocar exceções, mesmo que o motivo da falha tenha sido resolvido. De forma semelhante, um disjuntor automático pode aumentar e reduzir os tempos de respostas de aplicações se mudar demasiado rapidamente do estado Aberto para o estado Meio-Aberto.
Testando operações com falha: No estado Aberto, em vez de usar um temporizador para determinar quando alternar para o estado Semiaberto, um disjuntor pode, em vez disso, executar periodicamente ping no serviço remoto ou recurso para determinar se ele está disponível novamente. Este ping pode assumir a forma de uma tentativa de invocar uma operação que tinha anteriormente falhado, ou poderá utilizar uma operação especial fornecida pelo serviço remoto especificamente para testar o estado de funcionamento do serviço, conforme descrito pelo Padrão de Monitorização do Estado de Pontos Finais.
Substituição manual: Em um sistema onde o tempo de recuperação de uma operação com falha é extremamente variável, é benéfico fornecer uma opção de reinicialização manual que permite que um administrador feche um disjuntor (e redefina o contador de falhas). Da mesma forma, um administrador pode forçar um disjuntor no estado Open (e reiniciar o temporizador de tempo limite) se a operação protegida pelo disjuntor estiver temporariamente indisponível.
Simultaneidade: O mesmo disjuntor pode ser acessado por um grande número de instâncias simultâneas de um aplicativo. A implementação não deve bloquear pedidos simultâneos ou adicionar uma carga 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, num arquivo de dados que contenha diversas partições, uma partição poderá estar totalmente acessível, ficando a outra com um problema temporário. Se as respostas de erro nesses cenários forem unidas, uma aplicação poderá tentar aceder a algumas partições mesmo quando uma falha for provável, enquanto que o acesso a outras partições poderá estar bloqueado, não obstante as boas probabilidades de sucesso.
Interruptor acelerado: Às vezes, uma resposta de falha pode conter informações suficientes para que o disjuntor tropece imediatamente e permaneça tropeçado por um período mínimo de tempo. Por exemplo, a resposta de erro de um recurso partilhado que está sobrecarregado poderá indicar que uma nova tentativa imediata não é recomendada e que a aplicação deverá tentar novamente em poucos minutos.
Implantações em várias regiões: Um disjuntor pode ser projetado para implantações de uma ou várias regiões. Este último pode ser implementado usando balanceadores de carga globais ou estratégias personalizadas de circuit breaking com reconhecimento de região que garantem failover controlado, otimização de latência e conformidade normativa.
Disjuntores de malha de serviço: Os disjuntores podem ser implementados na camada de aplicação ou como um recurso transversal e abstrato. Por exemplo, as malhas de serviço geralmente suportam a quebra de circuito como um de sidecar ou como um recurso autônomo sem modificar o código do aplicativo.
Nota
Um serviço pode 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 no momento. A resposta pode incluir informações adicionais, como a duração prevista do atraso.
Reproduzir solicitações com falha: No estado Open, em vez de simplesmente falhar rapidamente, um disjuntor também pode registrar os detalhes de cada solicitação em um diário e providenciar 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 ser capaz de proteger totalmente os aplicativos contra operações que falham em serviços externos configurados com um longo período de tempo limite. Se o tempo limite for muito longo, uma rosca que executa um disjuntor pode ser bloqueada por um longo período antes que o disjuntor indique que a operação falhou. Durante este período, muitas outras instâncias de aplicações poderão também tentar invocar o serviço através do disjuntor automático e ligar um número significativo de threads antes de todas falharem.
Adaptabilidade à diversificação computacional: Os disjuntores devem levar em conta diferentes ambientes de computação, desde cargas de trabalho sem servidor até cargas de trabalho em contêineres, onde fatores como arranques a frio e escalabilidade afetam o tratamento de falhas. As abordagens adaptativas podem ajustar dinamicamente as estratégias com base no tipo de computação, garantindo resiliência em arquiteturas heterogêneas.
Quando utilizar este padrão
Utilize este padrão:
- Para evitar falhas em cascata interrompendo invocações excessivas por um serviço remoto ou solicitações de acesso a um recurso compartilhado se essas operações tiverem alta probabilidade de falhar.
- Para aumentar a resiliência de várias regiões, roteando o tráfego de forma inteligente com base em sinais de falha em tempo real.
- Para proteger contra dependências lentas, ajudando-o a acompanhar seus SLOs (Service Level Objetives, objetivos de nível de serviço) e a evitar a degradação do desempenho devido a serviços de alta latência.
- Para lidar com problemas intermitentes de conectividade e reduzir falhas de solicitação em ambientes distribuídos.
Este padrão não é recomendado:
- Para lidar com o acesso a recursos privados locais em um aplicativo, como uma estrutura de dados na memória. Neste ambiente, utilizar um disjuntor automático adicionaria uma sobrecarga ao seu sistema.
- Como substituto para processar exceções na lógica de negócio das suas aplicações.
- Quando algoritmos de repetição bem conhecidos são suficientes e suas dependências são projetadas para lidar com mecanismos de repetição. A implementação de um disjuntor na sua aplicação, neste caso, pode adicionar complexidade desnecessária ao seu sistema.
- Ao esperar por um disjuntor para redefinir pode introduzir atrasos inaceitáveis.
- Se você tiver uma arquitetura orientada por mensagem ou por eventos, pois eles geralmente encaminham mensagens com falha para uma fila de mensagens mortas (DLQ) para processamento manual ou adiado. Os mecanismos internos de isolamento e repetição de falhas normalmente implementados nesses projetos geralmente são suficientes.
- Se a recuperação de falhas for 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, os disjuntores podem não ser necessários.
Design da carga de trabalho
Um arquiteto deve avaliar como o padrão Disjuntor pode ser usado no design de sua carga de trabalho para abordar as metas e princípios abordados nos pilares do Azure Well-Architected Framework. Por exemplo:
Pilar | Como esse padrão suporta os objetivos do pilar |
---|---|
As decisões de projeto de confiabilidade ajudam sua carga de trabalho a se tornar resiliente ao mau funcionamento e a garantir que ela se recupere para um estado totalmente funcional após a ocorrência de uma falha. | Esse padrão evita sobrecarregar uma dependência com falha. Você também pode usar esse padrão para acionar a degradação normal na carga de trabalho. Os disjuntores são frequentemente acoplados à recuperação automática para fornecer autopreservação e auto-cura. - RE:03 Análise do modo de falha - RE:07 Falhas transitórias - RE:07 Autopreservação |
A Eficiência de Desempenho ajuda sua carga de trabalho a atender às demandas de forma eficiente por meio de otimizações em escala, dados e código. | Esse padrão evita a abordagem de repetição em erro, que pode levar à utilização excessiva de recursos durante a recuperação de dependência e também pode sobrecarregar o desempenho em uma dependência que está tentando recuperar. - PE:07 Código e infraestrutura - PE:11 Respostas a questões em direto |
Como em qualquer decisão de design, considere quaisquer compensações em relação aos objetivos dos outros pilares que possam ser introduzidos com esse padrão.
Exemplo
Este exemplo mostra o padrão de Disjuntor implementado para evitar a saturação de cota usando a camada gratuita vitalícia do Azure Cosmos DB. Essa camada é usada principalmente para dados não críticos, a taxa de transferência é regida por um plano de capacidade que provisiona uma cota designada de unidades de recursos por segundo. Durante eventos sazonais, a demanda pode exceder a capacidade fornecida, resultando em respostas 429
(muitas solicitações).
Quando ocorrem picos de demanda, o Azure Monitor alerta com limites dinâmicos deteta e notifica proativamente as equipes de operações e gerenciamento indicando que o dimensionamento da capacidade do banco de dados pode ser necessário. Simultaneamente, um disjuntor — ajustado usando padrões de erro históricos — aciona para evitar falhas em cascata. Nesse estado, o aplicativo se degrada graciosamente ao retornar respostas padrão ou armazenadas em cache, informando os usuários sobre a indisponibilidade temporária de certos dados, preservando a estabilidade geral do sistema.
Esta estratégia potencia a resiliência alinhada com a justificação do negócio. O controle de picos de capacidade permite que a equipe de carga de trabalho gerencie aumentos de custos deliberadamente e a qualidade do serviço seja mantida sem inflar inesperadamente as despesas operacionais. Uma vez que a demanda diminui ou o aumento da capacidade é confirmado, e o disjuntor é reiniciado e o aplicativo retorna à funcionalidade total em alinhamento com os objetivos técnicos e orçamentários.
O diagrama está organizado em três seções primárias. A primeira seção contém dois ícones idênticos do navegador da Web, onde o primeiro ícone exibe uma interface de usuário totalmente funcional, enquanto o segundo ícone mostra uma experiência de usuário degradada com um aviso na tela para indicar o problema aos usuários. A segunda seção é encerrada dentro de um retângulo tracejado, que é dividido em dois grupos. O grupo superior inclui os recursos de carga de trabalho, que consistem nos Serviços de Aplicativo do Azure e no Azure Cosmos DB. As setas de ambos os ícones do navegador da Web apontam para a instância dos Serviços de Aplicativo do Azure, representando solicitações de entrada do cliente. Além disso, as setas da instância dos Serviços de Aplicativo do Azure apontam para o Azure Cosmos DB, indicando as interações de dados entre os serviços de aplicativo e o banco de dados. Uma seta adicional faz um loop da instância dos Serviços de Aplicativo do Azure de volta para si mesma, simbolizando o mecanismo de tempo limite do disjuntor. Esse loop significa que, quando uma resposta 429 Too Many Requests é detetada, o sistema volta a servir respostas em cache, degradando a experiência do usuário até que a situação se resolva. O grupo inferior desta seção se concentra na observabilidade e alerta, apresentando o Azure Monitor coletando dados dos recursos do Azure no grupo superior e conectado a um ícone de regra de alerta. A terceira seção ilustra o fluxo de trabalho de escalabilidade acionado após o alerta que está sendo gerado. Uma seta conecta o ícone de alerta aos aprovadores, indicando que a notificação é enviada a eles para revisão. Outra seta leva dos aprovadores para um console de desenvolvimento, significando o processo de aprovação para dimensionar o banco de dados. Finalmente, uma seta subsequente se estende do console de desenvolvimento para o Azure Cosmos DB, representando a ação de dimensionar o banco de dados em resposta à condição de sobrecarga.
Fluxo A - Estado fechado
- O sistema funciona normalmente e todas as solicitações chegam ao banco de dados sem retornar nenhuma resposta HTTP
429
(muitas solicitações). - O disjuntor permanece fechado e nenhuma resposta padrão ou em cache é necessária.
Fluxo B - Estado aberto
- Ao receber a primeira resposta
429
, o disjuntor viaja para um estado aberto. - As solicitações subsequentes são imediatamente curto-circuitadas, retornando respostas padrão ou armazenadas em cache enquanto informam os usuários sobre degradação temporária, e o aplicativo é protegido contra sobrecargas adicionais.
- Os logs e os dados de telemetria são capturados e enviados ao Azure Monitor para serem avaliados em relação aos limites dinâmicos. Um alerta é acionado se as condições da regra de alerta forem atendidas.
- Um grupo de ação notifica proativamente a equipe de operações sobre a condição de sobrecarga.
- Após a aprovação da equipe de carga de trabalho, a equipe de operações pode aumentar a taxa de transferência provisionada para aliviar a sobrecarga, ou pode atrasar o dimensionamento se a carga diminuir naturalmente.
Fluxo C - Estado semiaberto
- Após um tempo limite predefinido, o disjuntor entra em um estado semiaberto, permitindo um número limitado de solicitações de teste.
- Se essas solicitações de avaliação forem bem-sucedidas sem retornar
429
respostas, o disjuntor será redefinido para um estado fechado, restaurando as operações normais de volta ao Fluxo A. Se as falhas persistirem, ele será revertido para o estado aberto que é o Fluxo B.
Desenho
- Serviços de Aplicativo do Azure hospeda o aplicativo Web atuando como o principal ponto de entrada para solicitações de clientes. 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 evita a sobrecarga nos sistemas downstream e garante que a experiência do usuário seja mantida durante picos de demanda ou falhas.
- do Azure Cosmos DB é um dos armazenamentos de dados do aplicativo. Ele serve dados não críticos usando o nível gratuito. O nível gratuito é melhor usado para executar 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.
-
Azure Monitor funciona como a solução de monitoramento centralizado, agregando todos os logs de atividades para garantir uma observabilidade abrangente de ponta a ponta. Os logs e dados de telemetria dos Serviços de Aplicativo do Azure e as principais métricas do Azure Cosmos DB (como o número de respostas
429
) são enviados ao Azure Monitor para agregação e análise. -
alertas do Azure Monitor pesar as regras de alerta em relação aos limites dinâmicos para identificar possíveis interrupções com base em dados históricos. Os alertas predefinidos notificam a equipe de operações quando os limites são violados. Pode haver momentos em que a equipe de carga de trabalho aprove o aumento na taxa de transferência provisionada, mas a equipe de operações antecipa que o sistema se recuperará por conta própria, pois a carga não é muito alta. Nestes casos, o tempo limite do disjuntor decorre naturalmente. Durante esse tempo, se as respostas
429
cessarem, o cálculo do limite deteta as interrupções prolongadas e as exclui do algoritmo de aprendizagem. Como resultado, da próxima vez que ocorrer uma sobrecarga, o limite aguardará uma taxa de erro mais alta no Azure Cosmos DB e a notificação será atrasada. Essa mudança permite que o disjuntor lide com o problema sem um alerta imediato, e eficiências nos custos e carga operacional são realizadas.
Recursos relacionados
Os padrões seguintes podem também ser úteis ao implementar este padrão:
O padrão de aplicativo Web confiável mostra como aplicar o padrão de disjuntor a aplicativos Web convergentes na nuvem.
Padrão Repetição. Descreve como uma aplicação pode processar falhas previstas e temporárias quando tentar ligar a um recurso ou serviço de rede, ao repetir de forma transparente uma operação que falhou anteriormente.
Padrão de monitoramento de ponto final de integridade. Um disjuntor automático pode conseguir testar o estado de um serviço ao enviar um pedido ao ponto final exposto pelo serviço. O serviço deve devolver informações a indicar o seu estado.