Nota de transparência acadêmica: este artigo apresenta um estudo de caso hipotético, elaborado para fins didáticos. O experimento, a arquitetura e os resultados descritos não foram executados nem medidos em uma infraestrutura real. Os números são parâmetros ilustrativos, e os resultados são formulados como expectativas a serem verificadas, não como evidências empíricas.
Resumo
Sistemas distribuídos podem apresentar falhas de rede, aumento de latência e indisponibilidade de dependências, situações capazes de afetar componentes além daqueles em que o problema começou. A Engenharia do Caos (Chaos Engineering) propõe investigar esse tipo de comportamento por meio de experimentos controlados, hipóteses verificáveis e observação de métricas relevantes. Este artigo apresenta uma aplicação conceitual desse método usando o ChaosEngineeringMasterDeck, tratado aqui como um catálogo didático de cartas de experimento, e não como uma ferramenta padronizada ou produto cuja existência esteja sendo afirmada. O cenário simula a introdução de latência na comunicação entre um serviço de pedidos e um serviço de pagamentos. São discutidos o estado estável, a hipótese, o raio de impacto, as condições de aborto, a observabilidade e padrões de resiliência como timeout, Bulkhead e Circuit Breaker. Por se tratar de uma simulação, o texto não comprova a eficácia de uma arquitetura real; ele apresenta um plano de experimento e os sinais que deveriam ser coletados para avaliar a hipótese.
Palavras-chave: Engenharia do Caos; resiliência; sistemas distribuídos; observabilidade; microsserviços; tolerância a falhas.
1. Introdução: da prevenção à resiliência
Em sistemas distribuídos, falhas podem ocorrer em diferentes camadas: uma rede pode apresentar latência, um banco de dados pode ficar temporariamente indisponível, um serviço externo pode responder lentamente ou um recurso computacional pode atingir sua capacidade. Além disso, mesmo quando os componentes funcionam isoladamente, suas interações podem produzir comportamentos inesperados. Os princípios de Engenharia do Caos destacam justamente a importância de observar o comportamento sistêmico sob condições adversas, em vez de considerar apenas o funcionamento individual dos componentes [1].
A Engenharia do Caos (Chaos Engineering) é uma abordagem experimental para investigar se um sistema mantém um comportamento aceitável quando exposto a condições que podem ocorrer no mundo real. Um experimento típico começa com a definição de um estado estável mensurável, formula uma hipótese, introduz uma variável adversa e compara o comportamento observado com o esperado [1].
Essa abordagem complementa testes unitários, testes de integração, testes de carga e revisões de código. Esses métodos continuam importantes, mas não necessariamente revelam todos os efeitos produzidos por dependências lentas, limites de recursos ou falhas que se propagam entre serviços. Por exemplo, chamadas que permanecem abertas por muito tempo podem aumentar a ocupação de threads e conexões, contribuindo para a degradação de outras operações. A Engenharia do Caos ajuda a testar hipóteses sobre esses efeitos de maneira controlada [1].
A mudança de perspectiva pode ser resumida em dois pontos:
- Prevenção isolada: tentar impedir todas as falhas e reagir quando elas acontecem.
- Resiliência: reconhecer que falhas são possíveis e projetar, observar e testar mecanismos que limitem seus efeitos.
Isso não significa provocar falhas indiscriminadamente. Os experimentos precisam ter objetivos definidos, monitoramento adequado, limites de impacto e condições claras de interrupção. Para um primeiro exercício, um ambiente isolado de teste ou pré-produção reduz a exposição. Experimentos em produção podem fornecer evidências mais representativas do tráfego real, mas exigem autorização, salvaguardas operacionais e contenção rigorosa do impacto [1].
2. O ChaosEngineeringMasterDeck como modelo conceitual
A Engenharia do Caos depende de método: injetar falhas sem hipótese, métricas ou limites pode causar indisponibilidade sem gerar aprendizado útil. Os princípios da prática recomendam formular hipóteses sobre o estado estável, introduzir eventos relevantes e tentar refutar a hipótese por meio de observações [1].
Neste artigo, o ChaosEngineeringMasterDeck é usado como um modelo conceitual para organizar experimentos em “cartas”. Essa denominação representa a proposta didática deste estudo e não implica que exista uma ferramenta padronizada com essa implementação.
Cada carta pode registrar:
- categoria e descrição da falha;
- componente-alvo;
- estado estável e hipótese;
- variável de injeção;
- métricas de observação;
- raio de impacto (blast radius);
- condições de aborto;
- procedimento de recuperação e evidências a registrar.
Essa estrutura transforma a ideia geral de “testar uma falha” em um experimento documentado e revisável.
2.1. Estado estável (steady state)
O estado estável descreve, por meio de indicadores mensuráveis, o comportamento considerado normal. A definição deve priorizar resultados observáveis, como latência, taxa de erros e vazão, em vez de depender apenas de sinais internos, como o fato de um processo estar em execução [1].
Para o cenário hipotético deste artigo, poderiam ser estabelecidos os seguintes objetivos iniciais:
- latência p99 do serviço de pedidos abaixo de 400 ms;
- utilização do pool de conexões abaixo de 60%;
- taxa de erros HTTP 5xx abaixo de 0,1%;
- capacidade de registrar pedidos sem perda de dados.
Esses números são ilustrativos, não recomendações universais. Em um sistema real, os limites deveriam ser definidos com base nos requisitos do produto, na linha de base observada, nos objetivos de nível de serviço e na capacidade da infraestrutura.
2.2. Hipótese experimental
Uma hipótese deve ser clara o suficiente para ser confirmada ou refutada por evidências. No cenário proposto:
Hipótese: se o serviço de pagamentos apresentar latência elevada, o serviço de pedidos limitará o tempo de espera, evitará a saturação de recursos compartilhados e, quando as regras de negócio permitirem, registrará o pedido como pendente sem afirmar que o pagamento foi concluído.
A hipótese reúne três aspectos distintos: limitar a espera, conter a propagação da falha e preservar a correção do estado do pedido. Cada aspecto exige sinais de observabilidade e critérios de avaliação próprios.
2.3. Variável de injeção
A variável de injeção é a condição adversa introduzida deliberadamente no experimento. Exemplos incluem latência de rede, perda de pacotes, interrupção de uma dependência ou restrição de largura de banda. Ferramentas como o Chaos Mesh permitem modelar falhas de rede em ambientes Kubernetes, incluindo atrasos e perda de pacotes [2].
Neste estudo, a variável escolhida é a latência artificial na comunicação com o serviço de pagamentos.
2.4. Raio de impacto (blast radius)
O blast radius representa a extensão máxima do impacto permitida. Ele pode ser limitado a um ambiente de teste, a um conjunto específico de instâncias ou a uma parcela controlada do tráfego. A contenção do impacto é um princípio importante da Engenharia do Caos, especialmente quando experimentos são realizados em ambientes compartilhados ou de produção [1].
Quanto menor e mais bem definido for o raio inicial, mais simples tende a ser identificar o efeito do experimento e interrompê-lo se algo inesperado ocorrer.
2.5. Condição de aborto (stop condition)
A condição de aborto estabelece quando o experimento deve parar. Ela pode considerar aumento de erros, degradação da latência de operações não relacionadas, saturação de recursos ou qualquer violação dos limites aprovados.
O plano deve definir como remover a injeção, confirmar a recuperação e comunicar a interrupção. O procedimento de remoção precisa ser considerado antes do início do teste, não improvisado durante um incidente.
3. Estudo de caso simulado: latência no serviço de pagamentos
Considere uma arquitetura hipotética de processamento de pedidos composta por microsserviços desenvolvidos em Java com Spring Boot, executados em Kubernetes na AWS EKS, com PostgreSQL para persistência e RabbitMQ para comunicação assíncrona.
O fluxo principal envolve dois componentes:
-
order-service: recebe e registra os pedidos; -
payment-gateway-service: integra-se ao serviço responsável pelo pagamento.
Uma dependência lenta pode prolongar chamadas síncronas e ocupar recursos enquanto o sistema aguarda uma resposta. O impacto concreto depende da concorrência, dos limites de tempo, do modelo de execução e dos recursos compartilhados.
O objetivo proposto é avaliar se a aplicação limita a espera pela dependência e mantém a capacidade de atender operações que não dependem diretamente dela.
3.1. Carta selecionada
Identificação: NET-04
Nome: Latência em dependência crítica
Categoria: Rede e dependências síncronas
| Atributo | Especificação proposta |
|---|---|
| Componente observado | Comunicação entre order-service e payment-gateway-service
|
| Falha injetada | Latência artificial de 2.500 ms, com jitter de até 200 ms |
| Hipótese | O serviço de pedidos limita a espera e evita que a lentidão degrade endpoints não relacionados |
| Métricas | Latência p50/p95/p99, erros HTTP 5xx, threads ocupadas, conexões do pool e estado do Circuit Breaker |
| Duração máxima | Até 5 minutos, condicionada aos critérios de segurança |
| Ambiente inicial recomendado | Ambiente de teste isolado, sem tráfego real de clientes |
Os valores são parâmetros acadêmicos de exemplo. Antes de uma execução real, seria necessário verificar a sintaxe e os campos exigidos pela versão da ferramenta, a seleção exata dos componentes e a compatibilidade com a infraestrutura.
3.2. Definição do raio de impacto
O plano considera um ambiente de teste isolado e uma instância canário do order-service. A injeção deve afetar apenas a comunicação prevista, sem atingir outros serviços ou tráfego não relacionado.
Antes de iniciar, a equipe deveria confirmar que:
- o seletor identifica somente o componente-alvo;
- o tráfego de teste está separado do tráfego real;
- a injeção pode ser removida rapidamente;
- métricas e alertas estão funcionando;
- o procedimento de aborto foi verificado;
- existe uma pessoa responsável por acompanhar o experimento.
Em uma implantação real, restringir o experimento a uma instância ou porcentagem específica de tráfego exige mecanismos de seleção e roteamento devidamente configurados. Declarar que o teste atinge, por exemplo, 5% do tráfego não garante, por si só, que o isolamento foi implementado.
3.3. Exemplo conceitual de configuração
O exemplo abaixo ilustra a aparência de um manifesto YAML para um experimento NetworkChaos no Chaos Mesh. A documentação da ferramenta descreve o uso desse recurso para simular condições de rede, incluindo atraso [2]. Ainda assim, o trecho é ilustrativo e não deve ser aplicado diretamente em um cluster: seletores, namespace, campos obrigatórios e comportamento da versão instalada precisam ser conferidos na documentação correspondente.
# Exemplo didático: validar antes de qualquer execução.
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: payment-latency-injection
namespace: test-canary
spec:
action: delay
mode: one
selector:
namespaces:
- test-canary
labelSelectors:
app: payment-gateway-service
delay:
latency: "2500ms"
correlation: "100"
jitter: "200ms"
duration: "5m"
O manifesto demonstra a intenção de simular atraso, mas não comprova que a configuração implementa todo o isolamento descrito. A direção do tráfego, o componente selecionado e a recuperação da injeção devem corresponder à hipótese experimental. A documentação do Chaos Mesh também destaca pré-requisitos operacionais para simulações de rede e a necessidade de manter a comunicação necessária à recuperação da falha [2].
3.4. Condições de aborto
Neste cenário, o teste seria interrompido se:
- a taxa de erros ultrapassasse o limite aprovado;
- a latência de endpoints não relacionados aumentasse de forma significativa;
- o uso de threads ou conexões se aproximasse de níveis críticos;
- a injeção afetasse componentes fora do escopo;
- o sistema não pudesse remover a falha de forma confiável.
Como exemplo acadêmico, poderia ser definido um limite de 1% de erros HTTP 5xx durante a janela de observação. Esse limiar não é universal: em um ambiente real, precisaria ser justificado pela linha de base e pelos objetivos de serviço. Após a interrupção, a equipe deveria confirmar a remoção da injeção e acompanhar se as métricas retornaram aos intervalos esperados.
4. Observabilidade e padrões de resiliência
A observabilidade ajuda a entender não apenas que ocorreu uma degradação, mas também onde ela começou, como se propagou e quais recursos foram afetados. A instrumentação de aplicações pode produzir sinais como métricas, rastros distribuídos e logs, que oferecem perspectivas complementares sobre o comportamento do sistema [3].
Para o cenário proposto, três fontes de informação seriam úteis:
- Métricas com Prometheus e Grafana: acompanhar latência p50, p95 e p99, taxa de erros, CPU, memória, threads ocupadas, conexões do pool e estado do Circuit Breaker.
- Rastreamento distribuído com OpenTelemetry e um backend de rastreamento, como Jaeger: identificar a duração de cada etapa da requisição e localizar a dependência que introduziu a demora.
- Logs centralizados: investigar timeouts, exceções, tentativas repetidas e acionamentos de tratamento alternativo.
OpenTelemetry é um framework de observabilidade independente de fornecedor para instrumentar, gerar, coletar e exportar dados de telemetria, incluindo rastros, métricas e logs [3]. As ferramentas listadas são exemplos de uma possível implementação; o estudo de caso não pressupõe que tenham sido instaladas ou utilizadas em ambiente real.
4.1. Fluxo hipotético
[Cliente]
|
| POST /orders
v
[order-service]
|
| chamada com limite de tempo
v
[TimeLimiter / Circuit Breaker / Bulkhead]
|
+---- chamada normal ----> [payment-gateway-service]
|
+---- falha ou timeout --> [tratamento alternativo]
|
v
[RabbitMQ, se aplicável]
|
v
[processamento posterior]
O diagrama representa uma possibilidade arquitetural, não um fluxo implementado ou observado. A fila só é apropriada se as regras de negócio permitirem o processamento posterior e se o sistema conseguir preservar a consistência do pedido e do pagamento. O cliente não deve receber uma confirmação de pagamento quando a transação ainda não foi confirmada.
4.2. O risco de novas tentativas (retries)
No cenário proposto, uma chamada ao serviço de pagamentos demora 2.500 ms. Se houver três tentativas sequenciais, cada uma consumindo esse tempo integral, a espera acumulada poderá chegar a aproximadamente 7,5 segundos, sem contar outros tempos de processamento. Esse cálculo é apenas ilustrativo e pressupõe que as três chamadas ocorram sequencialmente.
Chamadas prolongadas podem manter recursos ocupados. Quando muitas requisições se acumulam, isso pode contribuir para saturação de threads e conexões, dependendo da implementação e do nível de concorrência. Por esse motivo, novas tentativas precisam ser limitadas e configuradas em conjunto com os timeouts e os demais mecanismos de resiliência. O Resilience4j oferece módulos para padrões como Retry, Circuit Breaker, Bulkhead e TimeLimiter, que podem ser combinados de acordo com as necessidades da aplicação [4].
Também é necessário considerar a idempotência: repetir uma solicitação de pagamento sem proteção adequada pode gerar efeitos duplicados. A estratégia de repetição deve levar em conta o tipo de operação, a possibilidade de confirmar o resultado de uma tentativa anterior e os recursos de idempotência oferecidos pelo provedor de pagamento.
4.3. Mecanismos de resiliência propostos
Três mecanismos poderiam ser avaliados no experimento.
Timeout e TimeLimiter. Definem um limite para a espera por uma operação. Um valor ilustrativo de 1.000 ms permitiria tratar a chamada como excedida antes de aguardar os 2.500 ms completos, desde que o limite esteja aplicado corretamente. É importante verificar se o cancelamento da operação subjacente é realmente suportado: encerrar a espera do chamador não garante, por si só, que o trabalho remoto ou a execução subjacente tenha sido interrompido.
Bulkhead. Limita a concorrência ou separa recursos dedicados a uma dependência, reduzindo a possibilidade de que uma integração degradada consuma todos os recursos disponíveis. Um limite hipotético de 15 execuções concorrentes poderia ser testado, mas o valor adequado dependeria de medições de carga e da capacidade do serviço. O Resilience4j oferece implementações de Bulkhead com semáforos e com pool de threads, cada uma com características distintas [4].
Circuit Breaker e tratamento alternativo. O Circuit Breaker pode interromper temporariamente chamadas quando os critérios configurados indicam que uma dependência está falhando ou respondendo lentamente. O limiar deve ser definido e validado a partir do comportamento esperado da aplicação, e não escolhido apenas por conveniência. O Resilience4j disponibiliza esse padrão, além de mecanismos de fallback e outros decoradores de tolerância a falhas [4].
Se a regra de negócio permitir, o sistema poderá persistir o pedido com estado pendente e encaminhar o processamento do pagamento para uma fila. Nesse caso, a resposta deve deixar claro que o pagamento ainda não foi confirmado. O código HTTP 202 Accepted pode ser apropriado quando a solicitação foi aceita para processamento, mas não indica que a operação financeira foi concluída.
4.4. Exemplo didático em Java
O trecho a seguir ilustra a intenção de proteger uma chamada com mecanismos do Resilience4j. Ele é esquemático e não constitui uma implementação pronta para produção. O uso correto das anotações depende das dependências, da configuração, do modelo de execução e das assinaturas dos métodos. O Resilience4j documenta esses padrões e suas possibilidades de composição [4].
@CircuitBreaker(
name = "paymentService",
fallbackMethod = "queuePaymentForLater"
)
@Bulkhead(
name = "paymentService",
type = Bulkhead.Type.THREADPOOL
)
@TimeLimiter(name = "paymentService")
public CompletableFuture<PaymentResponse> processPayment(
OrderRequest request) {
return CompletableFuture.supplyAsync(
() -> paymentClient.charge(request)
);
}
Em uma implementação real, o método de fallback deve ter uma assinatura compatível com o método protegido e com a exceção recebida. A equipe também precisa verificar se a combinação de anotações e o tipo de retorno são compatíveis com a versão utilizada. O trecho, isoladamente, não demonstra que o pedido será publicado de forma confiável na fila.
A persistência do pedido, a publicação da mensagem e o processamento posterior precisam ser desenhados para lidar com falhas entre essas etapas. Por exemplo, a aplicação deve prever o que acontece se o pedido for salvo, mas a publicação da mensagem falhar. Essas decisões são parte da correção do fluxo de negócio e não são resolvidas apenas pela presença de um Circuit Breaker ou de um fallback.
4.5. Resultados hipotéticos e critérios de avaliação
Como o experimento não foi executado, não há medições reais a relatar. A tabela apresenta comportamentos que seriam investigados e evidências necessárias para avaliar a hipótese.
| Indicador | Risco a investigar antes dos ajustes | Evidência desejada após os ajustes |
|---|---|---|
| Latência da chamada de pagamento | Espera prolongada devido à dependência lenta | Chamadas limitadas conforme o timeout configurado |
| Uso de threads e conexões | Acúmulo de requisições em espera | Concorrência contida pelos limites configurados |
| Circuit Breaker | Chamadas continuam sendo realizadas durante a degradação | Transição de estado coerente com os critérios configurados |
| Endpoints independentes | Degradação causada por recursos compartilhados | Métricas permanecem dentro dos objetivos definidos |
| Estado do pedido | Resposta ambígua ou estado inconsistente | Estado pendente explícito quando aplicável e sem falsa confirmação de pagamento |
| Recuperação | Falha continua ativa ou o serviço não se recupera | Remoção da injeção e retorno das métricas à faixa esperada |
Para verificar os resultados em um teste real, seria necessário registrar a configuração usada, coletar uma linha de base, medir o comportamento durante a injeção e acompanhar a recuperação depois de removê-la. Se possível, uma comparação entre grupo de controle e grupo experimental ajudaria a distinguir o efeito da variável injetada de mudanças externas [1]. Até que esse procedimento seja executado, os resultados da última coluna são objetivos de validação, não resultados comprovados.
5. Discussão
O cenário evidencia que a resiliência não depende de um mecanismo isolado. Um timeout pode limitar a espera do chamador, mas não resolve automaticamente a consistência do pagamento. Um Bulkhead pode restringir a concorrência, mas precisa de limites coerentes com a capacidade do sistema. Um Circuit Breaker pode reduzir chamadas a uma dependência degradada, mas depende de critérios adequados e de um comportamento alternativo seguro [4].
Da mesma forma, a observabilidade não consiste apenas em instalar ferramentas. É necessário definir quais sinais respondem à hipótese e garantir que eles possam ser consultados durante o experimento. Métricas ajudam a identificar tendências e limites; rastros distribuídos ajudam a localizar a duração das etapas; logs oferecem detalhes sobre eventos e exceções. A instrumentação com OpenTelemetry pode apoiar a coleta de sinais de telemetria de forma independente de fornecedor [3].
O caso também reforça a importância de distinguir a aceitação de um pedido da confirmação de pagamento. Se o sistema adotar processamento assíncrono, o estado apresentado ao usuário deve corresponder ao que realmente foi confirmado. A resiliência técnica não pode ser obtida à custa de estados de negócio incorretos.
6. Conclusão
Este estudo de caso simulado apresenta uma forma de estruturar um experimento de Engenharia do Caos para investigar a latência em uma dependência crítica. A proposta combina uma hipótese verificável, a definição do estado estável, uma variável de injeção, a limitação do raio de impacto, condições de aborto e métricas de observação, em linha com os princípios publicados para a prática [1].
O ChaosEngineeringMasterDeck, conforme definido neste artigo, funciona como um catálogo conceitual para documentar experimentos. Seu valor didático está em organizar perguntas que precisam ser respondidas antes, durante e depois de um teste: o que será afetado, qual comportamento se espera, quais sinais serão observados e em que condições o experimento será interrompido.
Entre os benefícios esperados de uma abordagem como essa estão:
- Diagnóstico mais fundamentado: métricas, rastros e logs podem ajudar a localizar gargalos e a compreender a propagação de falhas.
- Maior contenção do impacto: limites de concorrência e um raio de experimento reduzido podem diminuir a chance de uma falha localizada afetar todo o sistema.
- Comportamento mais previsível: timeouts, Circuit Breakers e tratamentos alternativos podem controlar a resposta diante de dependências degradadas.
- Melhor colaboração entre desenvolvimento e operações: hipóteses, métricas e critérios de interrupção documentados favorecem decisões compartilhadas.
Esses benefícios dependem de planejamento, implementação correta e validação. O exercício apresentado não comprova que uma arquitetura real resistiu à falha; ele descreve como um experimento poderia ser estruturado e quais evidências seriam necessárias para avaliar sua eficácia.
A resiliência não deve ser presumida apenas porque uma aplicação utiliza ferramentas ou padrões conhecidos. Ela precisa ser investigada por meio de hipóteses claras, experimentos seguros, observação sistemática e resultados documentados com transparência.
Referências
[1] PRINCIPLES OF CHAOS ENGINEERING. Princípios de Chaos Engineering. Disponível em: https://principlesofchaos.org/pt/.
[2] CHAOS MESH. Simulate Network Faults. Documentação do Chaos Mesh. Disponível em: https://chaos-mesh.org/docs/next/simulate-network-chaos-on-kubernetes/.
[3] OPENTELEMETRY. Documentation. Disponível em: https://opentelemetry.io/docs/.
[4] RESILIENCE4J. Getting Started. Documentação do Resilience4j. Disponível em: https://resilience4j.readme.io/docs/getting-started.
Top comments (0)