Resiliência de aplicativos e infraestrutura

Concluído

Resiliência é a capacidade de recuperar de falhas transitórias. A estratégia de recuperação do aplicativo restaura a função normal com impacto mínimo no usuário. Falhas podem acontecer em ambientes de nuvem, e seu aplicativo deve responder de forma a minimizar o tempo de inatividade e a perda de dados. Em uma situação ideal, seu aplicativo lida com falhas graciosamente sem que o usuário saiba que houve um problema.

Como os ambientes de microsserviço podem ser voláteis, projete seus aplicativos para esperar e lidar com falhas parciais. Uma falha parcial, por exemplo, pode incluir exceções de código, interrupções de rede, processos de servidor sem resposta ou falhas de hardware. Mesmo atividades planeadas, como mover contêineres para um nó diferente dentro de um cluster Kubernetes, podem causar uma falha transitória.

Abordagens de resiliência

Ao projetar aplicativos resilientes, muitas vezes você tem que escolher entre falha rápida e degradação graciosa. Falhar rapidamente significa que o aplicativo lançará imediatamente um erro ou exceção quando algo der errado, em vez de tentar recuperar ou contornar o problema. Isso permite que os problemas sejam identificados e corrigidos rapidamente. A degradação normal significa que o aplicativo tentará continuar operando em uma capacidade limitada, mesmo quando algum componente falhar.

Em aplicativos nativos da nuvem, é importante que os serviços lidem com falhas normalmente, em vez de falhar rapidamente. Como os microsserviços são descentralizados e implantáveis de forma independente, são esperadas falhas parciais. Uma falha rápida permitiria que uma falha em um serviço derrubasse rapidamente os serviços dependentes, o que reduz a resiliência geral do sistema. Em vez disso, os microsserviços devem ser codificados para antecipar e tolerar falhas de serviço internas e externas. Essa degradação graciosa permite que o sistema geral continue operando mesmo se alguns serviços forem interrompidos. Funções críticas voltadas para o usuário podem ser mantidas, evitando uma interrupção completa. Uma falha normal também permite que os serviços perturbados tenham tempo para se recuperar ou se auto-curar antes de afetar o resto do sistema. Portanto, para aplicativos baseados em microsserviços, a degradação normal se alinha melhor às práticas recomendadas de resiliência, como isolamento de falhas e recuperação rápida. Evita que incidentes locais se espalhem em cascata pelo sistema.

Existem duas abordagens fundamentais para suportar uma degradação graciosa com resiliência: aplicação e infraestrutura. Cada abordagem tem vantagens e inconvenientes. Ambas as abordagens podem ser apropriadas dependendo da situação. Este módulo explica como implementar resiliência baseada em código e resiliência baseada em infraestrutura .

Resiliência baseada em código

Para implementar resiliência baseada em código, o .NET tem uma biblioteca de extensão para resiliência e tratamento de falhas transitórias, Microsoft.Extensions.Http.Resilience.

Ele usa uma sintaxe fluente e fácil de entender para criar código de tratamento de falhas de forma segura para threads. Existem várias políticas de resiliência que definem o comportamento de tratamento de falhas. Neste módulo, aplicam-se as estratégias de Retry e Circuit Breaker às operações do cliente HTTP.

Estratégia de repetição

Uma estratégia Retry é exatamente o que o nome indica. A solicitação é repetida após uma curta espera se uma resposta de erro for recebida. O tempo de espera aumenta a cada nova tentativa. O aumento pode ser linear ou exponencial.

Depois que o número máximo de tentativas é atingido, a estratégia desiste e lança uma exceção. Do ponto de vista do usuário, o aplicativo geralmente leva mais tempo para concluir algumas operações. O aplicativo também pode levar algum tempo antes de informar ao usuário que não foi possível concluir a operação.

Estratégia de Circuit Breaker

Uma estratégia de de disjuntor dá a um serviço alvo uma pausa após um número repetido de falhas, pausando a tentativa de comunicação com ele. O serviço pode estar a ter um problema grave e ficar temporariamente impossibilitado de responder. Após um número definido de falhas consecutivas, as tentativas de conexão são pausadas, abrindo o circuito. Durante essa espera, operações adicionais no serviço de destino falham imediatamente sem sequer tentar conectar o serviço. Após o tempo de espera, a operação é tentada novamente. Se o serviço responder com sucesso, o circuito é fechado e o sistema volta ao normal.

Resiliência baseada em infraestrutura

Para implementar a resiliência baseada em infraestrutura, você pode usar uma malha de serviço . Além da resiliência sem alterar o código, uma malha de serviço fornece gerenciamento de tráfego, política, segurança, identidade forte e observabilidade. Seu aplicativo é dissociado desses recursos operacionais, que são movidos para a camada de infraestrutura.

Comparação com abordagens baseadas em código

Uma abordagem de resiliência baseada em infraestrutura pode usar uma visão baseada em métricas que permite que ela se adapte dinamicamente às condições do cluster em tempo real. Essa abordagem adiciona outra dimensão ao gerenciamento do cluster, mas não adiciona nenhum código.

Com uma abordagem baseada em código, você:

  • São necessários para adivinhar quais parâmetros de repetição e tempo limite são apropriados.
  • Concentre-se em uma solicitação HTTP específica.

Não há uma maneira razoável de responder a uma falha de infraestrutura no código do seu aplicativo. Considere as centenas ou milhares de solicitações que estão sendo processadas simultaneamente. Mesmo uma nova tentativa com back-off exponencial (contagem de solicitações de tempos) pode inundar um serviço.

Por outro lado, as abordagens baseadas em infraestrutura desconhecem as funcionalidades internas das aplicações. Por exemplo, transações complexas de banco de dados são invisíveis para malhas de serviço. Tais transações só podem ser protegidas contra falhas com uma abordagem baseada em código.

Nas próximas unidades, você implementará resiliência para um aplicativo baseado em microsserviço usando resiliência HTTP .NET no código e uma malha de serviço Linkerd.