DEV Community

Rafael Magdaleno
Rafael Magdaleno

Posted on

Tolerância a Falhas em Sistemas Distribuídos: Como construir sistemas que sobrevivem ao caos

#a

Introdução
Imagine que você acessa um aplicativo de delivery às 20h de uma sexta-feira, no pico de pedidos, e ele simplesmente... funciona. Sem erro, sem lentidão, sem tela branca. Parece simples, mas por baixo desse "funciona" existe uma série de mecanismos sofisticados garantindo que falhas de rede, servidores sobrecarregados e bancos de dados instáveis não cheguem até você.
Esse conjunto de técnicas tem um nome: Tolerância a Falhas.
Em sistemas distribuídos — aqueles compostos por múltiplos serviços, servidores e redes se comunicando —, falhas não são exceção. Elas são inevitáveis. Um cabo de rede pode ser desconectado, um servidor pode travar, um serviço pode receber mais requisições do que suporta. A questão nunca é se vai falhar, mas quando — e o que o sistema fará quando isso acontecer.
Neste artigo, vamos entender o que é tolerância a falhas, por que ela é essencial e quais são as principais estratégias utilizadas no mundo real.

O que é Tolerância a Falhas?
Tolerância a Falhas é a capacidade de um sistema continuar operando corretamente mesmo quando parte dele falha. Um sistema tolerante a falhas não necessariamente evita os problemas — ele é projetado para detectá-los, isolá-los e se recuperar deles sem impacto perceptível para o usuário final.
Existem três propriedades que costumam andar juntas nesse contexto:

Disponibilidade (Availability): o sistema está acessível quando o usuário precisa dele.
Confiabilidade (Reliability): o sistema executa corretamente ao longo do tempo.
Resiliência: o sistema se recupera de falhas de forma automática ou controlada.

Por que isso é especialmente difícil em sistemas distribuídos?
Em um sistema monolítico rodando em um único servidor, quando algo falha, tudo falha junto — e a causa é mais fácil de isolar. Já em sistemas distribuídos, temos dezenas ou centenas de serviços independentes se comunicando pela rede. Isso cria desafios únicos:

Falhas parciais: um serviço pode falhar enquanto os outros continuam funcionando, gerando comportamentos inconsistentes.
Latência de rede: uma chamada que normalmente leva 50ms pode demorar 5 segundos em um momento de instabilidade — ou nunca retornar.
Ausência de memória compartilhada: cada serviço tem seu próprio estado, e sincronizá-los em caso de falha é complexo.
O problema dos dois exércitos: em redes não confiáveis, não há como garantir 100% que uma mensagem foi entregue e processada.

Principais estratégias de Tolerância a Falhas

  1. Redundância A estratégia mais clássica: se uma instância falha, outra assume. Isso pode ser aplicado em diferentes níveis:

Replicação de servidores: múltiplas instâncias do mesmo serviço rodando em paralelo.
Replicação de banco de dados: um nó primário e réplicas de leitura que assumem em caso de falha do primário.
Múltiplas regiões geográficas: o sistema está disponível em data centers diferentes, garantindo continuidade mesmo em desastres físicos.

A redundância é a base da alta disponibilidade. Serviços como Netflix, por exemplo, operam com replicação em múltiplas zonas de disponibilidade na AWS justamente para garantir que a falha de um data center inteiro não derrube o serviço.

  1. Circuit Breaker (Disjuntor)
    Imagine que o serviço de pagamento do seu e-commerce está com lentidão. Sem proteção, cada requisição vai esperar o timeout (digamos, 30 segundos) antes de falhar. Com 1000 usuários simultâneos, isso gera um acúmulo de threads esperando, que pode derrubar todo o sistema — um fenômeno chamado de falha em cascata.
    O Circuit Breaker funciona como um disjuntor elétrico: quando detecta que um serviço está falhando repetidamente, ele abre o circuito e passa a retornar erro imediatamente, sem tentar a chamada real. Após um tempo, ele testa novamente — se o serviço se recuperou, fecha o circuito; caso contrário, mantém aberto.
    Estados do Circuit Breaker:
    EstadoComportamentoFechadoChamadas normais passam. Falhas são monitoradas.AbertoChamadas são bloqueadas imediatamente. Retorna erro rápido.Meio-abertoAlgumas chamadas de teste são permitidas para verificar recuperação.
    Bibliotecas como Polly (.NET), Resilience4j (Java) e Hystrix (Netflix) implementam esse padrão amplamente no mercado.

  2. Retry com Backoff Exponencial
    Nem toda falha é permanente. Uma falha de rede momentânea pode se resolver em milissegundos. Estratégias de retry (nova tentativa) lidam com isso — mas com um detalhe importante: não tentar de forma agressiva.
    O backoff exponencial define um intervalo crescente entre as tentativas:
    Tentativa 1: aguarda 1 segundo
    Tentativa 2: aguarda 2 segundos
    Tentativa 3: aguarda 4 segundos
    Tentativa 4: aguarda 8 segundos...
    Isso evita que múltiplos clientes, ao falhar ao mesmo tempo, bombardeiem o serviço recuperando — o chamado thundering herd problem. Adicionar um fator aleatório (jitter) nas esperas distribui ainda mais as tentativas no tempo.

  3. Timeout
    Parece óbvio, mas é frequentemente negligenciado: toda chamada remota deve ter um tempo máximo de espera. Sem timeout, uma chamada pode ficar esperando indefinidamente, travando recursos do sistema.
    A regra de ouro: defina timeouts em todas as chamadas de rede, e calibre-os com base no comportamento esperado do serviço. Um serviço que normalmente responde em 100ms não deveria ter um timeout de 30 segundos.

  4. Fallback
    Quando uma operação falha e não pode ser repetida, o sistema pode recorrer a um fallback — um comportamento alternativo degradado, mas funcional.
    Exemplos práticos:

A lista de recomendações personalizadas falhou? Mostre os produtos mais vendidos em geral.
O serviço de CEP está fora? Peça ao usuário que preencha o endereço manualmente.
A cotação de câmbio em tempo real não carregou? Use a última cotação em cache.

O fallback garante que o sistema continua parcialmente operacional mesmo com falhas, em vez de apresentar uma tela de erro para o usuário.

  1. Health Checks e Observabilidade Para que um sistema tolerante a falhas funcione, ele precisa saber que está falhando. Isso envolve:

Health checks: endpoints que orquestradores (como Kubernetes) consultam para saber se um serviço está saudável. Se não estiver, o serviço é reiniciado ou removido do balanceamento de carga.
Métricas: taxas de erro, latência, throughput — monitorados em tempo real.
Logs estruturados: registros que permitem rastrear uma requisição por todos os serviços que ela percorreu.
Alertas automáticos: quando métricas saem do padrão esperado, a equipe é notificada antes que o usuário perceba.

Aplicação no Mundo Real
Grandes empresas investem pesado em tolerância a falhas. O próprio Netflix criou o conceito de Chaos Engineering — introduzir falhas propositalmente em produção para testar a resiliência do sistema. Sua ferramenta Chaos Monkey desligava servidores aleatoriamente durante o horário comercial, forçando a equipe a garantir que o sistema sobrevivesse.
A ideia central: se você nunca testou como seu sistema falha, você não sabe se ele é resiliente.

Conclusão
Tolerância a Falhas não é um recurso adicional que se adiciona ao sistema quando sobrar tempo — é uma propriedade fundamental de qualquer sistema distribuído que pretende operar em produção.
As estratégias apresentadas aqui — redundância, circuit breaker, retry com backoff, timeouts, fallbacks e observabilidade — não são mutuamente exclusivas. Sistemas robustos combinam todas elas em camadas, criando uma defesa em profundidade contra o inevitável: as falhas vão acontecer.
O diferencial de um bom engenheiro de software é não perguntar "e se nada falhar?", mas sim "e quando isso falhar, o que acontece?". Projetar para a falha é projetar para a realidade.

Referências

TANENBAUM, Andrew S.; VAN STEEN, Maarten. Sistemas Distribuídos: Princípios e Paradigmas. 2. ed. Pearson Prentice Hall, 2007.
NEWMAN, Sam. Building Microservices: Designing Fine-Grained Systems. 2. ed. O'Reilly Media, 2021.
FOWLER, Martin. CircuitBreaker. martinfowler.com, 2014. Disponível em: https://martinfowler.com/bliki/CircuitBreaker.html
NETFLIX TECHNOLOGY BLOG. Chaos Engineering. Disponível em: https://netflixtechblog.com/tagged/chaos-engineering

Top comments (0)