Simulador de Falhas

Simule falhas em produção — quedas de serviços, timeouts, erros de rede — e pratique estratégias de resiliência.

Objetivo

Neste laboratório você vai simular falhas comuns em sistemas distribuídos e praticar as estratégias de resiliência que as mitigam. Cada cenário apresenta uma falha, pede que você identifique o impacto e proponha uma solução.

Em produção, as falhas não avisam. Aqui você pode praticar sem consequências.

Cenário 1: Timeout em cascata

A falha

O serviço A chama o serviço B, que chama o serviço C. O serviço C começa a responder devagar (3 segundos em vez de 200ms). Ele não está fora do ar — apenas lento.

[Servicio A] ──timeout 5s──► [Servicio B] ──timeout 5s──► [Servicio C: LENTO 3s]

O que acontece?

  1. C responde em 3s → B espera 3s + seu próprio processamento (500ms) = 3.5s
  2. A espera 3.5s por B → os usuários veem latência de 4s+
  3. As threads de A e B ficam bloqueadas esperando → o pool de conexões se esgota
  4. Novos requests para A começam a falhar por timeout → cascata de falhas

Exercício: Projete a mitigação

Responda estas perguntas:

  1. Que timeout você colocaria em cada serviço?

    • Dica: os timeouts devem ser decrescentes na cadeia (A > B > C)
  2. Onde você colocaria um circuit breaker?

    • Dica: no ponto onde a falha se origina (B → C)
  3. Que resposta B daria quando o circuit breaker estivesse aberto?

    • Dica: resposta degradada, cache, ou erro rápido
  4. Como você detectaria esse problema antes que afetasse os usuários?

    • Dica: métricas de latência p99, alertas por percentil

Solução recomendada

Ver solução
[Servicio A]          [Servicio B]              [Servicio C]
  timeout: 2s           timeout: 1s               ---
                        circuit breaker: ON
                        fallback: caché local
                        bulkhead: pool separado
  • Timeouts decrescentes: A=2s, B=1s. Se C demorar mais de 1s, B corta imediatamente.
  • Circuit breaker em B→C: Após 5 falhas consecutivas, B para de chamar C por 30 segundos.
  • Fallback: Quando o circuit breaker está aberto, B responde com dados de cache (mesmo que estejam stale).
  • Bulkhead: B usa um pool de conexões separado para C, assim as falhas de C não esgotam as conexões para outros serviços.

Cenário 2: Banco de dados saturado

A falha

É Black Friday. O tráfego se multiplicou por 5x. O banco de dados PostgreSQL do serviço de catálogo está a 95% de CPU. As queries que normalmente levam 50ms agora levam 2 segundos. O connection pool está cheio.

Sintomas observados

  • Latência da API: p50 = 500ms (normal: 100ms), p99 = 8s (normal: 300ms)
  • Connection pool: 100/100 conexões em uso
  • CPU do PostgreSQL: 95%
  • Erros 503 no frontend: 15% dos requests

Exercício: Resposta imediata

Você está de plantão. O que faz nos próximos 30 minutos?

  1. Ação imediata (primeiros 5 minutos):

    • O que você pode fazer sem alterar código?
  2. Mitigação de curto prazo (próximos 25 minutos):

    • Quais mudanças de configuração ajudariam?
  3. Prevenção futura:

    • Quais mudanças arquiteturais evitariam esse problema?

Solução recomendada

Ver solução

Imediato (5 min):

  • Ativar modo somente leitura para operações não críticas
  • Aumentar o tamanho do connection pool se o servidor permitir
  • Habilitar a read replica se existir mas não estiver em uso

Curto prazo (25 min):

  • Ativar cache do Redis para as queries mais frequentes do catálogo
  • Reduzir o timeout de queries lentas para liberar conexões
  • Escalar verticalmente a instância do PostgreSQL (mais CPU/RAM)

Prevenção futura:

  • Implementar cache de leitura (Redis) como camada permanente
  • Adicionar read replicas para distribuir a carga de leitura
  • Implementar rate limiting para proteger o banco de dados
  • Configurar auto-scaling baseado em métricas de CPU/conexões
  • Revisar e otimizar as queries mais custosas (EXPLAIN ANALYZE)

Cenário 3: Mensagem perdida na fila

A falha

O serviço de pedidos publica um evento OrderCreated no RabbitMQ. O serviço de pagamentos consome esse evento e processa o pagamento. Mas um dia você descobre que 50 pedidos das últimas 24 horas nunca foram processados — o evento foi publicado, mas o serviço de pagamentos nunca o recebeu.

Investigação

O que pode ter acontecido? Analise cada possibilidade:

  1. A mensagem nunca chegou ao RabbitMQ

    • O publisher usa confirmações (publisher confirms)?
    • O que acontece se o RabbitMQ não responder ao publish?
  2. A mensagem chegou mas se perdeu no RabbitMQ

    • A fila é durable?
    • As mensagens são persistentes?
    • O RabbitMQ reiniciou e perdeu mensagens em memória?
  3. O consumer recebeu a mensagem mas falhou ao processá-la

    • O consumer faz ACK antes ou depois de processar?
    • Existe dead letter queue para mensagens que falham?
  4. O consumer estava fora do ar quando a mensagem chegou

    • A fila retém mensagens quando não há consumers?
    • Existe um TTL que expira mensagens não consumidas?

Exercício: Projete um sistema de mensageria resiliente

[Servicio de Órdenes]

    ▼ (publisher confirms)
[RabbitMQ]
    │ (cola durable, mensajes persistentes)

[Servicio de Pagos]
    │ (ACK después de procesar)

    ├── éxito → ACK
    └── fallo → NACK → Dead Letter Queue → alerta

Checklist de resiliência para mensageria

Ver checklist
  • Publisher confirms: O publisher espera a confirmação do RabbitMQ antes de considerar a mensagem enviada
  • Fila durable: A fila sobrevive a reinicializações do RabbitMQ
  • Mensagens persistentes: As mensagens são gravadas em disco, não apenas em memória
  • ACK manual: O consumer faz ACK somente depois de processar com sucesso
  • Dead letter queue: As mensagens que falham N vezes vão para uma fila separada para investigação
  • Idempotência: O consumer pode processar a mesma mensagem duas vezes sem efeitos duplicados
  • Monitoramento: Alertas quando a fila cresce mais do que o normal ou há mensagens na DLQ
  • Retry com backoff: As mensagens que falham são retentadas com delays crescentes

Cenário 4: Split brain no cache

A falha

Você tem um cluster de Redis com 3 nós (1 master + 2 replicas). Durante uma partição de rede, uma replica é promovida a master. Agora você tem 2 masters aceitando escritas com dados diferentes.

Impacto

  • Alguns usuários veem o preço antigo de um produto ($100)
  • Outros usuários veem o preço novo ($80)
  • Quando a partição se resolve, quais dados vencem?

Exercício

  1. Como você detectaria um split brain em produção?
  2. Qual estratégia de resolução você usaria? (last-write-wins, merge, manual)
  3. Como você preveniria esse cenário?
Ver solução

Detecção:

  • Monitorar o número de masters no cluster (alerta se > 1)
  • Sentinel ou Redis Cluster detectam automaticamente e resolvem

Resolução:

  • O Redis usa last-write-wins por padrão ao reconectar
  • Os dados do master “perdedor” são descartados
  • Para dados críticos (preços, estoque), a fonte da verdade deve ser o banco de dados, não o cache

Prevenção:

  • Configurar min-replicas-to-write para que o master rejeite escritas se não tiver quórum
  • Usar o Redis como cache (não como fonte da verdade) — sempre poder reconstruir a partir do banco
  • Implementar health checks que detectem partições de rede

Reflexão

Depois de completar os cenários:

  1. Quantas dessas falhas você já viu em produção?
  2. Seu sistema atual tem proteções contra esses cenários?
  3. Qual falha parece mais provável no seu contexto?
  4. Que ação concreta você pode tomar amanhã para melhorar a resiliência do seu sistema?

Os sistemas não falham de formas novas — falham das mesmas formas repetidamente. Conhecer os padrões de falha é a melhor preparação.