REL 5: Como você projeta interações em um sistema distribuído para mitigar ou resistir a falhas?
Os sistemas distribuídos dependem de redes de comunicação para interconectar componentes (como servidores ou serviços). Sua carga de trabalho deve operar de forma confiável, apesar da perda de dados ou da latência nessas redes. Os componentes do sistema distribuído devem operar sem afetar negativamente outros componentes ou a carga de trabalho. Essas melhores práticas permitem que as cargas de trabalho resistam a tensões ou falhas, recuperem-se mais rapidamente delas e reduzam o impacto de tais prejuízos. Como resultado, o Mean Time To Recovery (MTTR – Tempo médio até a recuperação) é melhorado.
Recursos
Retry, backoff, and jitter: AWS re:Invent 2019: Introducing The Amazon Builders’ Library
(DOP328)
Error Retries and Exponential Backoff in AWS
Amazon API Gateway: Throttle API Requests for Better Throughput
The Amazon Builders' Library: Timeouts, retries, and backoff with jitter
The Amazon Builders' Library: Avoiding fallback in distributed systems
The Amazon Builders' Library: Avoiding insurmountable queue backlogs
The Amazon Builders' Library: Caching challenges and strategies
Well-Architected lab: Level 300: Implementing Health Checks and Managing Dependencies
to Improve Reliability
CircuitBreaker (summarizes Circuit Breaker from “Release It!” book)
Michael Nygard “Release It! Design and Deploy Production-Ready Software”
Melhores práticas:
-
Implementar uma degradação simples para transformar dependências rígidas aplicáveis em dependências flexíveis: Quando as dependências de um componente não estão íntegras, o próprio componente ainda pode funcionar, embora de maneira prejudicada. Por exemplo, quando há falha em uma chamada de dependência, faça o failover para uma resposta estática predeterminada.
-
Solicitações de controle de utilização: Esse é um padrão de mitigação para responder a um aumento inesperado na demanda. Algumas solicitações são atendidas, mas aquelas que ultrapassam um limite definido são rejeitadas e retornam uma mensagem indicando que foram limitadas. A expectativa dos clientes é que eles recuem e abandonem a solicitação ou tentem novamente com uma taxa mais lenta.
-
Controle e limite as chamadas de repetição: Use o recuo exponencial para tentar novamente após intervalos progressivamente mais longos. Introduza uma variação para tornar esses intervalos de repetição aleatórios e limite o número máximo de novas tentativas.
-
Falha rápida e filas limitadas: Se a carga de trabalho não puder responder a uma solicitação com êxito, gere uma falha rápida. Isso permite a liberação dos recursos associados a uma solicitação e permite que o serviço se recupere se estiver ficando sem recursos. Se a carga de trabalho puder responder com êxito, mas a taxa de solicitações for muito alta, use uma fila para armazenar as solicitações em buffer. No entanto, não permita filas longas que possam levar ao fornecimento de solicitações obsoletas que o cliente já tinha descartado.
-
Defina tempos limite do cliente: Defina tempos limite adequados, verifique-os sistematicamente e não use valores padrão, já que eles costumam ser muito altos
-
Crie serviços sem estado sempre que possível: Os serviços não devem exigir estado ou devem descarregar o estado de modo que não haja dependência entre solicitações de clientes diferentes em relação aos dados armazenados localmente no disco ou na memória. Isso permite que os servidores sejam substituídos quando necessário sem prejudicar a disponibilidade. O Amazon ElastiCache ou o Amazon DynamoDB é um bom destino para o estado descarregado.
-
Implementar medidas emergenciais: Trata-se de processos rápidos que podem atenuar o impacto da disponibilidade sobre a carga de trabalho. Eles podem ser operados na ausência de uma causa raiz. Uma medida emergencial ideal reduz a carga cognitiva dos resolvedores a zero ao fornecer critérios de ativação e de desativação totalmente determinísticos. Alguns exemplos de medidas são o bloqueio de todo o tráfego de robô ou o fornecimento de uma resposta estática. Geralmente, as medidas são manuais, mas também podem ser automatizadas.
Plano de melhoria
Implementar uma degradação simples para transformar dependências rígidas aplicáveis
em dependências flexíveis
- Ao retornar uma resposta estática, a carga de trabalho atenua as falhas que ocorrem
nas dependências dela
Well-Architected lab: Level 300: Implementing Health Checks and Managing Dependencies to Improve Reliability - Detecte quando há probabilidade de falha na operação de repetição e impeça o cliente
de fazer chamadas com falha com o padrão de disjuntor
CircuitBreaker
Solicitações de controle de utilização
- Use o Amazon API Gateway
Throttle API Requests for Better Throughput
Controle e limite as chamadas de repetição
Error Retries and Exponential Backoff in AWS
- Por padrão, os SDKs da Amazon implementam esse procedimento. Implemente uma lógica semelhante em sua camada de dependência ao chamar seus próprios serviços dependentes. Decida quais são os tempos limite e quando parar de tentar novamente com base no seu caso de uso.
Falha rápida e filas limitadas
- Implementar uma falha rápida quando o serviço estiver sob pressão
Fail Fast - Filas limitadas: Em um sistema baseado em fila, quando o processamento é interrompido, mas as mensagens
continuam chegando, o débito de mensagens pode se acumular em uma lista grande de
pendências, o que aumenta o tempo de processamento. Os resultados podem deixar de
ser úteis por conta da demora na conclusão do trabalho, o que afeta principalmente
a disponibilidade que o enfileiramento tinha que proteger.
The Amazon Builders' Library: Avoiding insurmountable queue backlogs
Defina tempos limite do cliente
AWS SDK: Retries and Timeouts
Crie serviços sem estado sempre que possível
- Remova o estado que realmente pode ser armazenado nos parâmetros de solicitação.
- Alguns dados (como cookies) podem ser inseridos em cabeçalhos ou parâmetros de consulta.
- Faça a refatoração para remover o estado que pode ser inserido rapidamente nas solicitações.
- Depois de examinar se o estado é necessário, mova qualquer acompanhamento de estado
para um cache multizona resiliente ou um armazenamento de dados, como Amazon ElastiCache,
Amazon RDS, Amazon DynamoDB ou uma solução de dados distribuídos de terceiros: Armazene os estados que não puderam ser movidos para armazenamentos de dados resilientes.
- Alguns dados talvez não sejam realmente necessários por solicitação e podem ser recuperados sob demanda.
- Remova os dados que podem ser recuperados de forma assíncrona.
- Escolha um armazenamento de dados que atenda aos requisitos de um estado necessário.
- Considere um banco de dados NoSQL para dados não relacionais.
Implementar medidas emergenciais
- Dicas para implementar e usar medidas emergenciais
- Quando as medidas forem ativadas, faça MENOS, e não mais
- Simplifique, evite comportamento bimodal
- Teste suas medidas periodicamente
- Veja a seguir exemplos de ações que NÃO são medidas emergenciais
- Adicionar capacidade
- Chamar proprietários de serviços de clientes que dependem do seu serviço e solicitar que eles reduzam as chamadas
- Fazer uma alteração no código e lançá-lo