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?
- C responde em 3s → B espera 3s + seu próprio processamento (500ms) = 3.5s
- A espera 3.5s por B → os usuários veem latência de 4s+
- As threads de A e B ficam bloqueadas esperando → o pool de conexões se esgota
- Novos requests para A começam a falhar por timeout → cascata de falhas
Exercício: Projete a mitigação
Responda estas perguntas:
-
Que timeout você colocaria em cada serviço?
- Dica: os timeouts devem ser decrescentes na cadeia (A > B > C)
-
Onde você colocaria um circuit breaker?
- Dica: no ponto onde a falha se origina (B → C)
-
Que resposta B daria quando o circuit breaker estivesse aberto?
- Dica: resposta degradada, cache, ou erro rápido
-
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?
-
Ação imediata (primeiros 5 minutos):
- O que você pode fazer sem alterar código?
-
Mitigação de curto prazo (próximos 25 minutos):
- Quais mudanças de configuração ajudariam?
-
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:
-
A mensagem nunca chegou ao RabbitMQ
- O publisher usa confirmações (publisher confirms)?
- O que acontece se o RabbitMQ não responder ao publish?
-
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?
-
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?
-
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
- Como você detectaria um split brain em produção?
- Qual estratégia de resolução você usaria? (last-write-wins, merge, manual)
- 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-writepara 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:
- Quantas dessas falhas você já viu em produção?
- Seu sistema atual tem proteções contra esses cenários?
- Qual falha parece mais provável no seu contexto?
- 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.