Pular para o conteúdo

Conceitos

Padrões de resiliência: circuit breaker, bulkhead, timeout e retry com backoff

Intuição

Pense num restaurante que depende de um fornecedor de gelo que anda lento. Você não espera para sempre pela entrega (limite de tempo), tenta de novo mas com pausas cada vez maiores em vez de ligar a cada segundo, e, se o fornecedor claramente está fora do ar, para de ligar por um tempo e usa gelo de reserva. Além disso, você separa as bancadas da cozinha, para que um problema no balcão de sobremesas não trave o salão inteiro, como as divisórias de um navio impedem que um furo afunde tudo. O objetivo não é evitar que o fornecedor falhe, e sim impedir que a falha dele derrube o restaurante todo.

Como funciona

A primeira defesa é o timeout: toda chamada remota precisa de um prazo, porque sem ele threads e conexões ficam presas esperando um serviço lento e o problema se propaga para quem o chama. O retry recupera falhas transitórias, mas precisa ser limitado em número de tentativas e usar backoff exponencial com jitter (aleatoriedade no intervalo), para que muitos clientes não voltem todos ao mesmo tempo; retries ilimitados e sincronizados multiplicam a carga sobre um serviço já degradado e criam uma tempestade de retries (retry storm) que impede a recuperação. Retry só é seguro em operações idempotentes (repetir produz o mesmo efeito de executar uma vez) ou com chave de idempotência. O circuit breaker é uma máquina de três estados: fechado (chamadas passam e o breaker conta falhas e lentidão), aberto (ao passar de um limiar, falha imediatamente sem chamar a dependência, dando a ela tempo de se recuperar) e semi-aberto (após um intervalo, deixa passar poucas chamadas de teste; se tiverem sucesso volta a fechado, senão reabre). O bulkhead isola pools de recursos (threads, conexões, filas) por dependência ou por tipo de cliente, de modo que a saturação de um pool não consuma a capacidade dos demais. Complementam o conjunto o load shedding (rejeitar parte da carga cedo quando o sistema está saturado, para servir bem o restante) e o fallback ou degradação graciosa (devolver cache, valor padrão ou funcionalidade reduzida quando a dependência falha). O paper Tail at Scale mostra o contraponto controlado: o hedging só envia a segunda cópia após um tempo próximo ao p95, limitando a carga extra a poucos por cento, enquanto retries sem limite não têm esse teto. Esses padrões tratam falhas e saturação, enquanto hedging e tied requests tratam a variabilidade de latência de réplicas saudáveis.

Na prática

Esses padrões aparecem em bibliotecas e service meshes que oferecem timeouts, retries com backoff, circuit breakers e limites de conexões por destino, e são tratados em referências como 'Release It!' de Michael Nygard, no catálogo de padrões de nuvem do Microsoft Azure Architecture Center e nos artigos do AWS Builders' Library sobre timeouts, retries e backoff com jitter. Você os escolhe sempre que um serviço depende de outros pela rede, começando por timeouts em todas as chamadas, retries só onde há idempotência e um orçamento de tentativas, e circuit breaker e bulkhead nas dependências menos confiáveis ou não críticas. Experimentos de caos servem para verificar se esses mecanismos realmente seguram a falha na prática.

Use em um desenho

Pratique na escola de System Design os casos que dependem deste conceito.