Retries Distribuídos: Evitando o Thundering Herd

Mostrar/Ocultar
Introdução
Em sistemas distribuídos, é comum que várias instâncias de um mesmo serviço detectem simultaneamente uma falha em um endpoint externo e disparem retries ao mesmo tempo. Esse comportamento, conhecido como thundering herd, pode causar ainda mais sobrecarga no serviço alvo, gerando latências adicionais ou até quedas totais. Para superar esse desafio, adotamos padrões de retries distribuídos, nos quais um armazenamento compartilhado (por exemplo, Redis) atua como ponto único de verdade para coordenar quando cada instância pode tentar novamente.
O Desafio do “Thundering Herd”
- Picos sincronizados: sem coordenação, todas as instâncias reenviam requisições após um erro, criando um volume repentino de chamadas.
- Sobrecarregamento do serviço: o endpoint degradado recebe ainda mais demandas, agravando sua instabilidade.
- Inconsistência de falhas: cada nó tem seu próprio contador de tentativas, resultando em comportamentos diferentes e difícil monitoração centralizada.
Conceito de Retry Distribuído
- State store compartilhado
Um sistema externo (Redis, por exemplo) armazena o instante em que está autorizado o próximo retry para um dado recurso. - Back-off coordenado
Baseado em algoritmos de back-off exponencial, define-se um “calendário” global de tentativas que todas as instâncias consultam antes de tentar novamente. - Fonte única de verdade
Ao ler e escrever timestamps de próxima tentativa em um único local, evitamos divergências e duplicação de esforço.
Modelagem de Chave e Valor
- Chave única
Cada recurso ou grupo de chamadas recebe um identificador (por exemplo, o nome lógico do cliente ou serviço). - Valor timestamp
Armazena o instante (UTC) a partir do qual todas as instâncias podem re-tentar. - Tempo de expiração
Um TTL que garanta limpeza automática de valores antigos, evitando bloqueios indefinidos.
Fluxo de Retries Coordenados
- Falha detectada
Uma instância detecta erro em uma chamada e calcula o atraso do próximo retry (por exemplo, usando back-off exponencial). - Gravação no state store
Ela escreve no Redis o timestamp da próxima tentativa para aquele recurso, com TTL igual ao atraso. - Leitura antes do retry
Qualquer instância que queira re-tentar primeiro lê o valor armazenado. Se a hora atual for anterior ao timestamp, aguarda o tempo restante. - Execute quando liberado
Após o instante registrado, a instância faz a nova tentativa e, em caso de falha, repete o processo.
Benefícios
- Redução de carga no endpoint
Evita múltiplos retries simultâneos, distribuindo as solicitações ao longo do tempo. - Previsibilidade de comportamento
O padrão de atraso segue um cronograma global, facilitando a monitoração e o ajuste fino. - Simplicidade de operação
Usa um datastore leve e de alta performance, sem necessidade de brokers ou componentes complexos.
Cuidados Operacionais
- Latência do store
Cada operação de leitura/gravação no Redis adiciona overhead; monitore sua performance e recursos. - TTL apropriado
Defina um tempo de expiração que cubra o maior intervalo de back-off esperado, evitando chaves “zumbis”. - Fallback em caso de indisponibilidade
Se o Redis falhar, considere regressar a um back-off local até que a coordenação esteja restabelecida. - Monitoramento e métricas
Exponha contadores de retries, tempos de espera e falhas globais para dashboards e alertas.
Conclusão
A implementação de retries distribuídos usando um state store compartilhado é uma técnica eficaz para amenizar o thundering herd em arquiteturas com múltiplas instâncias. Ao coordenar atrasos em um ponto central, garantimos que o consumo de serviços degradados seja escalonado, melhorando a estabilidade geral do sistema. Essa abordagem equilibra simplicidade e robustez, oferecendo um caminho claro para tornar aplicações distribuídas mais resilientes.
Referências
- Martin Fowler – “Patterns of Enterprise Application Architecture”
- Documentação oficial do Redis e práticas recomendadas
Conecte-se para transformar sua tecnologia!
Saiba mais e entre em contato: