Como evitar “novas tempestades” nos serviços distribuídos?


10

Uma "tempestade de repetição" é causada quando os clientes são configurados para repetir um número definido de vezes antes de desistir, uma política de repetição é necessária porque a perda de pacotes ocorrerá na operação normal de um serviço.

Veja este exemplo:

Arquitetura de exemplo

Se, por exemplo, os serviços como um todo fossem dimensionados para suportar 80.000 solicitações por segundo e executados com cerca de 80% da capacidade, um pico no tráfego que fazia com que o serviço recebesse 101.000 solicitações por segundo causaria falha em 1.000 dessas solicitações.

Quando as políticas de repetição entram em ação, você acaba com mais de 1.000 solicitações, dependendo de onde a falha foi detectada, o que elevaria o serviço como um todo até 102.000 solicitações por segundo - a partir daí, o serviço entra em uma espiral mortal, dobrando o número de pedidos com falha a cada segundo.

Além do excesso de provisionamento maciço de serviços além da transação de pico projetada, o que seria ineficiente. Quais estratégias você pode empregar para evitar "tentar novamente tempestades"?


Se 100kQPS é 80% da capacidade, 101kQPS não deve resultar em falhas de 1k, deve resultar em zero falhas - não é esse o ponto de superprovisionamento?
26617 Adrian

@ Adrian, seu direito, foi um exemplo inventado para explicar o argumento - eu estava tentando ser redutivo o suficiente para deixar claro o argumento sem ser excessivamente abstrato. Corrigi o "dimensionado para suportar 100.000" para "dimensionado para suportar 80.000".
Richard Slater

Respostas:


7

Depende do que você está tentando evitar.

Se você está tentando evitar qualquer interrupção no serviço de algo que seja genuinamente crítico (estou pensando em termos de "as pessoas morrerão se minha chamada à API não for atendida adequadamente"), você precisará apenas fazer um orçamento para as enormes ineficiências que provêm muito do provisionamento de recursos dedicados. E sim, eles precisam ser dedicados, nada disso permite coisas de picos de tráfego, o picos de vários serviços causaria uma interrupção.

No cenário muito mais provável em que o serviço está sendo interrompido, seria inconveniente que você possa resolver o problema do lado do cliente e do servidor. Embora seja interessante notar que é logicamente impossível resolver o problema de muito tráfego, porque sem processar o tráfego (que consome recursos) você não pode saber se é uma nova tentativa, se é uma nova tentativa de uma solicitação que foi bem-sucedida, mas que foi tratada incorretamente pelo cliente, se for um DDOS, etc. Mas você pode mitigar o impacto.

No código do cliente, escreva uma lógica de repetição sensata, que possui um limite superior e um mecanismo para falhas delicadas. Dessa forma, você não coloca seus usuários em um loop infinito de solicitações com falha e apenas gera um erro dizendo a eles para tentarem o que eles fizeram em pouco tempo.

Para a infraestrutura do servidor, a solução mais simples é acelerar. Limites rígidos em solicitações, especialmente se você puder tentar espalhá-las logicamente com base em seu caso de uso específico (por exemplo, se você tiver um serviço centralizado tomar algumas decisões difíceis, deseja começar a bloquear solicitações geograficamente distantes que possam resultar em interrupções de encadeamento do lado do servidor? Ou você deseja distribuir sua inevitável, mas menor interrupção de maneira uniforme? etc) Tudo se resume ao fato de que retornar um 503 intencionalmente de um gateway é muito mais barato do que deixar a solicitação passar e enviar um 504 de qualquer forma. Basicamente, force os clientes a se comportarem com base no que você pode fornecer atualmente e forneça as respostas corretas para que os clientes possam reagir adequadamente.


5

Uma maneira de impedir essas novas tempestades é usando mecanismos de retirada.

Na seção Backoff do implemento ao tentar novamente do guia Design do Google App Engine para Scale :

Seu código pode tentar novamente com falha, seja para chamar um serviço como o Cloud Datastore ou um serviço externo usando o URL Fetch ou a API do soquete. Nesses casos, você sempre deve implementar uma política de retirada exponencial aleatória para evitar o problema do rebanho trovejante . Você também deve limitar o número total de novas tentativas e manipular falhas depois que o limite máximo de novas tentativas for atingido.

A maioria das APIs do GAE já possui esses mecanismos / políticas de retirada ativados por padrão.


Obrigado, a implementação de mecanismos de backoff é um ótimo conselho, eu geralmente busco o backoff exponencial configurável usando o bloco de aplicativos Transient Fault Handling Application . No entanto, através de mais de 5 anos de experiência operacional na operação de aplicativos de grande escala no Azure, mesmo com backoffs exponenciais "tempestades de repetição" ainda ocorrem com bastante frequência - nunca consegui encontrar uma estratégia viável para evitá-los.
Richard Slater
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.