O custo real de um retry
Retries adicionam carga bem na hora em que o sistema está mais fraco. Backoff, jitter, orçamento e breakers evitam a amplificação.
Um retry parece de graça. A chamada falhou, então você chama de novo. Qual seria o custo? Bem maior do que parece. Retry é a forma mais comum que já vi de um incidente pequeno virar uma queda completa, e a maioria dos times adiciona retries sem nunca decidir quanto eles deveriam custar.
O motivo é simples. Um retry adiciona carga exatamente na hora em que o sistema está menos preparado para aguentar. Uma dependência dá timeout porque está sobrecarregada. Seu cliente responde mandando a mesma requisição de novo. Agora a dependência está mais sobrecarregada ainda. Multiplique isso por todos os chamadores e você tem uma tempestade de retries.
A multiplicação que ninguém calcula
Imagine três camadas: um navegador, um API gateway e um serviço que fala com o banco de dados. Cada camada faz três retries em caso de falha. Quando o banco fica lento, uma única ação do usuário pode virar 3 x 3 x 3 = 27 chamadas ao banco. Vinte e sete. O banco já estava sofrendo com uma.
É essa aritmética que transforma uma query lenta em um cluster morto. Não é nada exótico. É o comportamento padrão da maioria dos clientes HTTP empilhados uns sobre os outros, cada um configurado por uma pessoa diferente que nunca viu o quadro inteiro.
Procuro isso em quase toda auditoria, e quase sempre encontro. Ninguém decidiu construir um amplificador de 27x. Só colocaram "retries: 3" em três arquivos de configuração separados.
Backoff, jitter e orçamento
A primeira correção é o backoff exponencial: espere 100 ms, depois 200, depois 400, depois 800. A segunda é o jitter, ou seja, aleatorizar essas esperas. Sem jitter, todo cliente que falhou no mesmo instante tenta de novo no mesmo instante, e você só agendou o próximo pico.
A terceira correção é a que a maioria dos times pula: um orçamento de retries. Em vez de permitir três retries por requisição, você permite que os retries sejam no máximo uma fração do tráfego total, digamos 10 por cento. Quando a taxa de falha passa disso, os retries param. O orçamento garante que um minuto ruim custe 1,1x de carga, não 27x.
Backoff e jitter dão forma ao retry. O orçamento limita. Você quer os três.
Tente de novo as coisas certas, nos erros certos
Um retry só é seguro se a operação for idempotente. Repetir uma leitura é tranquilo. Repetir "cobrar o cartão" quando a primeira tentativa deu timeout depois de a cobrança ter passado é cobrança dupla. Se uma operação não é idempotente, ou você a torna idempotente com uma chave de requisição, ou não faz retry automático. Deixe um humano ou um job de reconciliação decidir.
O código do erro também importa. Faça retry em timeout, em 503, em conexão resetada: condições transitórias que podem se resolver em segundos. Não faça retry em 400, 404 ou 422. A requisição estava errada. Mandar de novo com o mesmo payload é carga desperdiçada e, pior, esconde um bug atrás de uma parede de ruído.
O freio: circuit breakers
Retries são o acelerador. O circuit breaker é o freio. Quando as falhas passam de um limite, o breaker abre e as chamadas falham na hora, sem retry, por um período de resfriamento. Depois ele deixa passar um fio de requisições para testar se a dependência se recuperou.
Sem breaker, uma política de retry continua empurrando carga para uma dependência de joelhos. Com breaker, a dependência recebe a única coisa de que precisa para se recuperar: silêncio.
Os retries que você não enxerga
Os retries mais perigosos são os que o servidor não conhece. Apps mobile que tentam de novo por conta própria. Código no navegador com um wrapper de fetch que alguém escreveu dois anos atrás. Um service mesh com retries ligados por padrão. Um SDK com retries embutidos por baixo dos seus retries explícitos.
Quando você ajusta retries, está ajustando uma camada. O sistema faz retry em todas. Antes de decidir uma política, siga uma única requisição com falha do dedo do usuário até o disco e conte as tentativas. O número é quase sempre maior do que qualquer pessoa na sala esperava.
Um retry é uma aposta de que a segunda tentativa vai dar certo e de que o custo de tentar é pequeno. Faça essa aposta explicitamente, com backoff, jitter, orçamento, garantia de idempotência e um breaker. Senão você não está fazendo retry. Está amplificando.