Introdução ao Chaos Engineering
Chaos Engineering é a prática de injetar falhas controladas em um sistema para descobrir seus pontos fracos antes que um incidente real aconteça.
Por que quebrar coisas de propósito? Porque em sistemas distribuídos falhar é normal. É melhor descobrir um problema numa terça de manhã, com o time preparado, do que numa sexta à noite com o cliente reclamando.
A mudança de mentalidade é simples:
- Antes: "Vamos evitar que o sistema falhe."
- Agora: "O sistema vai falhar. Vamos garantir que ele aguente."
Conceitos-chave:
- Estado estável: o comportamento normal do sistema, medido por métricas (ex.: taxa de erro, latência).
- Blast radius: o tamanho máximo do estrago que aceitamos causar no experimento.
- Observabilidade: logs, métricas e traces para enxergar o que está acontecendo.
Dissecando o ChaosEngineeringMasterDeck
O ChaosEngineeringMasterDeck é um baralho de cartas de experimento. Cada carta descreve uma falha para testar, de forma padronizada. Nas nossas Game Days, sorteamos uma carta e executamos o experimento.
Toda carta tem:
- Hipótese: o que esperamos que aconteça.
- Variável: a falha que vamos injetar.
- Métricas de controle: como saber se o sistema continua saudável.
- Blast radius: o limite do impacto.
- Condição de aborto: quando parar tudo.
Exemplo de carta:
id: CARD-014
nome: "A Lentidão Silenciosa"
hipotese: "Com +2s de latência no payment-service, o checkout continua >= 95%."
variavel: latencia de 2000ms em 25% das requisicoes
metricas: [taxa_checkout_concluido, latencia_p99, taxa_erro_5xx]
blast_radius: "1 pod, 5% do trafego, 10 minutos"
aborto: "checkout < 90% por 60s"
Estudo de Caso: A Lentidão Silenciosa
Arquitetura: e-commerce na AWS, com microsserviços em Spring Boot rodando no EKS. O checkout-service chama o payment-service, e usa Resilience4j para resiliência.
Carta sorteada: CARD-014, que simula alta latência no serviço de pagamento.
Blast radius:
- Apenas 1 pod do
payment-service - Cerca de 5% do tráfego
- Duração máxima de 10 minutos
- Primeiro em staging, depois em produção-canário
Hipótese: o Circuit Breaker vai abrir e o fallback vai enfileirar os pagamentos, mantendo o checkout acima de 95%.
Trecho do fallback testado:
@CircuitBreaker(name = "paymentService", fallbackMethod = "pagarAsync")
public PedidoResultado finalizarPedido(Pedido pedido) {
return paymentClient.cobrar(pedido);
}
private PedidoResultado pagarAsync(Pedido pedido, Throwable ex) {
paymentQueue.enfileirar(pedido);
return PedidoResultado.pendentePagamento(pedido.getId());
}
Observabilidade e Resultados
Monitoramos tudo com Prometheus + Grafana (métricas) e Jaeger (traces).
O que aconteceu:
- O Circuit Breaker abriu depois de cerca de 80 segundos.
- O fallback assumiu e o checkout ficou em 97%.
- O alerta de latência disparou como esperado.
A arquitetura sobreviveu? Sim, com ressalvas. O experimento mostrou problemas:
- O Circuit Breaker demorou demais para abrir (janela grande).
- O Retry dobrou a carga no serviço lento.
- O Auto Scaling não reagiu, porque olhava só a CPU e não a latência.
Padrões em ação: Circuit Breaker, Fallback e Timeout funcionaram. Retry e Auto Scaling precisaram de ajuste.
Conclusão
Lições aprendidas:
- Resiliência é uma hipótese: só se confirma testando.
- Configurações padrão precisam ser calibradas.
- Comece pequeno: blast radius reduzido, risco reduzido.
- Sem observabilidade, não existe experimento.
Na cultura DevOps, o ganho maior foi mudar a postura do time: falhas deixam de ser motivo de culpa e viram oportunidade de aprendizado. Descobrir um problema num experimento planejado é muito melhor do que descobrir num incidente real.
Top comments (0)