Resumo. Sistemas distribuídos em nuvem estão sujeitos a falhas parciais que dificilmente são reproduzidas por testes funcionais convencionais. Neste artigo, apresento o Chaos Engineering como disciplina experimental voltada à verificação empírica da resiliência e descrevo o ChaosEngineeringMasterDeck, framework que minha equipe utiliza para estruturar experimentos de caos em cartas padronizadas, compostas por hipótese, variável injetada, métricas de controle, Blast Radius e condição de aborto. Como estudo de caso, relato a aplicação da carta REDE-07, que injeta latência na comunicação entre dois microsserviços Spring Boot executados no Amazon EKS. A primeira execução refutou nossa hipótese de resiliência e evidenciou o esgotamento do pool de threads causado pela ausência de limite de tempo nas chamadas remotas. Após adotarmos de forma combinada os padrões Time Limiter, Bulkhead, Circuit Breaker e Fallback, a segunda execução confirmou a hipótese. Concluo que a prática converte suposições sobre resiliência em evidências mensuráveis e fortalece a responsabilidade compartilhada característica da cultura DevOps.
Palavras-chave: Chaos Engineering; resiliência; sistemas distribuídos; microsserviços; observabilidade; DevOps.
1. Introdução
Atuo como engenheiro de software em uma equipe responsável por uma plataforma de comércio eletrônico baseada em microsserviços. Ao longo da migração dessa plataforma para a nuvem, percebi que a mesma arquitetura que nos trouxe escalabilidade e autonomia também aumentou de forma expressiva a complexidade operacional do sistema. Em uma arquitetura distribuída, cada chamada de rede representa um ponto potencial de falha, e a interação entre componentes produz comportamentos emergentes que não se manifestam em testes isolados. Falhas parciais, como degradação de latência, perda de uma zona de disponibilidade ou indisponibilidade temporária de um banco de dados, tendem a se propagar em cascata quando os mecanismos de proteção não foram adequadamente configurados.
Foi nesse contexto que minha equipe passou a adotar o Chaos Engineering, definido como a disciplina de realizar experimentos sobre um sistema com o objetivo de construir confiança em sua capacidade de suportar condições turbulentas em produção (BASIRI et al., 2016). A prática foi sistematizada pela Netflix durante a migração de sua infraestrutura para a Amazon Web Services, quando a empresa desenvolveu o Chaos Monkey, ferramenta que encerra instâncias aleatoriamente em produção para forçar o projeto de serviços tolerantes à perda de nós (BASIRI et al., 2016).
1.1 Justificativa: por que provocar falhas intencionalmente
O argumento que me convenceu a defender essa prática internamente é simples: falhas em sistemas distribuídos são inevitáveis. Quando aceito essa premissa, a pergunta relevante deixa de ser se o sistema falhará e passa a ser como ele se comportará quando falhar. Ao provocarmos falhas em condições controladas, com a equipe disponível, monitoramento ativo e plano de reversão definido, conseguimos descobrir fragilidades a um custo significativamente menor do que o de um incidente não planejado.
Os testes automatizados que já mantínhamos verificam se o sistema produz o resultado esperado sob condições conhecidas. O Chaos Engineering, por sua vez, investiga o comportamento do sistema sob condições adversas realistas, frequentemente associadas a configurações de infraestrutura, volume de tráfego e interações entre serviços que existem apenas em produção.
1.2 Mudança de paradigma
Adotar a prática exigiu de mim e da minha equipe uma mudança na forma de conceber a confiabilidade, que sintetizo no Quadro 1.
Quadro 1 – Comparação entre a abordagem tradicional e a abordagem do Chaos Engineering
| Dimensão | Abordagem tradicional | Abordagem do Chaos Engineering |
|---|---|---|
| Objetivo | Evitar a ocorrência de falhas | Garantir a continuidade do serviço apesar das falhas |
| Fonte de confiança | Testes funcionais aprovados | Falhas reais suportadas sob observação |
| Natureza dos incidentes | Eventos inesperados | Hipóteses previamente testadas |
| Resiliência | Presumida a partir do projeto | Verificada empiricamente |
Fonte: elaborado pelo autor.
1.3 Princípios fundamentais
Para orientar nossos experimentos, adotei como referência os Princípios de Chaos Engineering (PRINCIPLES OF CHAOS ENGINEERING, 2019), que estabelecem cinco diretrizes:
- Formular uma hipótese em torno do estado estável (steady state), definido por métricas observáveis de negócio e de sistema, e não pela simples disponibilidade dos servidores.
- Variar eventos do mundo real, injetando falhas que efetivamente ocorrem em produção, como latência, perda de nós e esgotamento de recursos.
- Executar experimentos em produção ou no ambiente que mais se aproxime dela.
- Automatizar os experimentos para que sejam executados continuamente.
- Minimizar o *Blast Radius*, isto é, limitar o escopo do impacto potencial e ampliá-lo apenas à medida que a confiança no sistema aumenta.
Nas seções seguintes, descrevo como operacionalizamos esses princípios por meio do ChaosEngineeringMasterDeck e relato um estudo de caso de sua aplicação.
2. O ChaosEngineeringMasterDeck
2.1 Definição
O ChaosEngineeringMasterDeck é o framework que minha equipe desenvolveu para padronizar e priorizar experimentos de caos. Cada experimento é representado por uma carta, que possui uma versão impressa, utilizada em sessões presenciais de simulação que chamamos de GameDays, e uma versão em arquivo YAML versionado no repositório do projeto. Essa dupla representação nos permite conduzir o mesmo experimento manualmente, para fins de aprendizado coletivo, ou de forma automatizada, como etapa recorrente do pipeline de entrega.
Concebemos o framework para resolver três limitações que eu havia observado em nossa prática anterior:
- Ausência de padronização: cada engenheiro descrevia experimentos de uma forma, o que impedia a comparação de resultados.
- Ausência de salvaguardas: iniciávamos experimentos sem condições de interrupção previamente definidas.
- Baixo engajamento: a prática era percebida pelo time como atividade adicional e desvinculada do desenvolvimento. O formato de baralho introduziu um componente de gamificação que, na minha experiência, favoreceu a participação conjunta das equipes de desenvolvimento e operações.
2.2 Organização por naipes e severidade
Agrupamos as cartas em quatro naipes, cada um correspondente a uma camada da arquitetura, conforme o Quadro 2.
Quadro 2 – Naipes do ChaosEngineeringMasterDeck
| Naipe | Camada | Exemplos de experimentos |
|---|---|---|
| Rede | Comunicação entre serviços | Latência elevada, perda de pacotes, partição de rede, falha de resolução DNS |
| Computação | Instâncias, contêineres e zonas | Encerramento de pods, saturação de CPU, perda de uma zona de disponibilidade |
| Dados | Bancos de dados, cache e filas | Failover de banco de dados, indisponibilidade de cache, acúmulo de mensagens |
| Dependências | Serviços internos e externos | Indisponibilidade de gateway de pagamento, API externa retornando HTTP 503 |
Fonte: elaborado pelo autor.
Cada carta possui ainda um nível de severidade de 1 a 5. Estabelecemos uma regra de progressão segundo a qual equipes iniciantes executam apenas cartas de níveis 1 e 2, e cartas de níveis 4 e 5, como a perda de uma região inteira, só são habilitadas após a execução bem-sucedida das cartas de menor severidade do mesmo naipe. Com essa regra, aplicamos o princípio de minimização do Blast Radius no nível do programa de experimentos, e não apenas no nível de cada experimento individual.
2.3 Estrutura de uma carta
Estruturei as cartas de acordo com as etapas do método científico. A Figura 1 apresenta o modelo que utilizamos.
Figura 1 – Modelo de carta do ChaosEngineeringMasterDeck
+------------------------------------------------+
| [NAIPE]-[NÚMERO] Severidade: N |
| Título do experimento |
+------------------------------------------------+
| HIPÓTESE |
| Se [falha], então [estado estável se mantém],|
| porque [mecanismo de resiliência]. |
| |
| ESTADO ESTÁVEL métricas e valores-base |
| VARIÁVEL INJETADA tipo, intensidade, tempo |
| BLAST RADIUS limite máximo de impacto |
| CONDIÇÃO DE ABORTO critérios de interrupção |
| ROLLBACK procedimento de reversão |
+------------------------------------------------+
Fonte: elaborado pelo autor.
Os campos têm as seguintes funções:
- Hipótese: deve ser formulada obrigatoriamente no padrão "Se [falha], então [o estado estável se mantém], porque [mecanismo de resiliência]". Insisti na exigência da cláusula causal porque ela impede que executemos experimentos nos quais não conseguimos identificar o mecanismo que deveria proteger o sistema, o que por si só já constitui um achado relevante.
- Estado estável: conjunto de métricas que caracterizam o comportamento normal do sistema, com seus respectivos valores de referência.
- Variável injetada: a variável independente do experimento, especificada por tipo, alvo, intensidade, proporção do tráfego afetado e duração.
- Métricas de controle: as mesmas métricas do estado estável, que comparamos entre um grupo de controle, não submetido à falha, e um grupo experimental.
- Blast Radius: delimitação do impacto máximo admissível em termos de ambiente, usuários, serviços e tempo.
- Condição de aborto: limiares cuja violação interrompe o experimento automaticamente.
3. Estudo de Caso: Latência em Dependência Crítica
3.1 Nota metodológica
O cenário que descrevo nesta seção é um estudo de caso construído para fins didáticos. A arquitetura, as configurações e os procedimentos refletem práticas reais de mercado. Os valores numéricos que apresento nas Tabelas 1 e 2 são ilustrativos: defini-os de modo a manter coerência interna entre as métricas, e eles não correspondem a medições de um ambiente produtivo específico.
3.2 Arquitetura do sistema
A plataforma em que trabalho é composta por microsserviços desenvolvidos em Spring Boot e executados no Amazon Elastic Kubernetes Service (EKS), distribuídos em três zonas de disponibilidade na região sa-east-1 (São Paulo). A Figura 2 apresenta o fluxo de criação de pedidos, que consideramos o fluxo crítico do negócio.
Figura 2 – Fluxo de criação de pedidos
+-------------+
Cliente -------> | API Gateway |
+------+------+
|
+------v---------+ +-------------------+
| order-service | ----> | inventory-service |
| (Spring Boot | | (Spring Boot) |
| + Resilience4j)| +---------+---------+
+------+---------+ |
| +-------v-------+
+------v--------+ | Amazon RDS |
|payment-service| | (PostgreSQL) |
+---------------+ +---------------+
Fonte: elaborado pelo autor.
O order-service consulta o inventory-service de forma síncrona para verificar a disponibilidade de estoque antes de confirmar cada pedido. Por se tratar de uma dependência síncrona situada no caminho crítico, identifiquei sua degradação como o principal risco de propagação de falhas em nossa arquitetura.
3.3 Especificação do experimento
A carta que selecionamos para o GameDay foi a REDE-07, cuja especificação apresento na Listagem 1.
Listagem 1 – Especificação da carta REDE-07
id: REDE-07
naipe: rede
severidade: 2
titulo: "Latência na Dependência Crítica"
hipotese: >
Se o inventory-service responder com acréscimo de 2000 ms de latência,
a taxa de sucesso na criação de pedidos permanecerá acima de 99%
e a latência p99 do order-service permanecerá abaixo de 800 ms,
porque o Circuit Breaker será aberto e o fallback utilizará
o cache de estoque.
estado_estavel:
- metrica: taxa_sucesso_pedidos
referencia: ">= 99.5%"
- metrica: latencia_p99_order_service
referencia: "< 450 ms"
- metrica: pedidos_por_minuto
referencia: "variação < 5% em relação ao grupo de controle"
variavel_injetada:
tipo: latencia
alvo: order-service -> inventory-service
latencia_ms: 2000
jitter_ms: 300
percentual_trafego: 10
duracao: 10m
ferramenta: toxiproxy
blast_radius:
ambiente: producao-canary
escopo: "pods do order-service no grupo canary (5% dos usuários)"
impacto_maximo: "aproximadamente 0,5% das requisições de criação de pedido"
servicos_excluidos: [payment-service, auth-service]
condicao_aborto:
- "taxa de erro HTTP 5xx no canary > 2% por mais de 1 minuto"
- "latência p99 no canary > 3000 ms por mais de 2 minutos"
- "disparo de qualquer alerta de severidade P1"
rollback: "remoção do toxic de latência no Toxiproxy"
Fonte: elaborado pelo autor.
3.4 Delimitação do Blast Radius
O Blast Radius corresponde à extensão máxima do impacto caso a hipótese se revele falsa. Neste experimento, delimitei-o em três dimensões complementares:
- Ambiente: restringimos o experimento ao grupo canary, que recebe 5% do tráfego real por meio de roteamento ponderado no API Gateway.
-
Tráfego: dentro do grupo canary, submetemos à latência apenas 10% das chamadas ao
inventory-service. - Tempo: fixamos a duração máxima em 10 minutos, com interrupção automática em caso de violação das condições de aborto.
O produto dessas restrições resulta em um impacto máximo estimado de 0,5% das requisições de criação de pedido durante, no máximo, 10 minutos. Antes da execução, apresentei esse nível de risco à área de produto, que o aceitou formalmente.
Optei pelo ambiente produtivo, e não apenas pelo de homologação (staging), com base no terceiro princípio do Chaos Engineering. Em minha experiência, volume de tráfego, padrões de acesso e dimensionamento de pools de conexão raramente são reproduzidos com fidelidade em homologação, e diversas fragilidades de resiliência só se manifestam sob carga real. Para equipes em estágio inicial de maturidade, contudo, considero o ambiente de homologação um ponto de partida adequado.
3.5 Injeção da falha
Injetei a latência por meio do Toxiproxy, proxy TCP de código aberto desenvolvido pela Shopify para simulação de condições adversas de rede (SHOPIFY, 2024). Implantamos o proxy como contêiner auxiliar (sidecar) nos pods do order-service, interceptando as conexões destinadas ao inventory-service. A Listagem 2 apresenta o comando que utilizei.
Listagem 2 – Injeção de latência com o Toxiproxy
toxiproxy-cli toxic add \
--type latency \
--attribute latency=2000 \
--attribute jitter=300 \
--toxicity 0.1 \
--toxicName latency_inventory \
inventory
Fonte: elaborado pelo autor.
4. Observabilidade e Resultados
4.1 Instrumentação
Antes de injetar qualquer falha, precisei garantir que conseguíamos medir o estado estável. A instrumentação que utilizamos foi composta pelos seguintes elementos:
- Micrometer e Prometheus: coleta de métricas dos serviços Spring Boot por meio do Spring Boot Actuator.
- Grafana: painel que criei especificamente para o experimento, com exibição simultânea das métricas do grupo de controle e do grupo canary.
- OpenTelemetry e Jaeger: rastreamento distribuído para identificar como o tempo de resposta se distribuía entre os serviços.
- Alertmanager: avaliação contínua das condições de aborto.
A Listagem 3 apresenta as consultas PromQL que utilizei para as principais métricas de controle.
Listagem 3 – Consultas PromQL das métricas de controle
# Latência p99 do order-service, segmentada por grupo
histogram_quantile(0.99,
sum(rate(http_server_requests_seconds_bucket{service="order-service", uri="/orders"}[1m]))
by (le, group)
)
# Taxa de erros HTTP 5xx, segmentada por grupo
sum(rate(http_server_requests_seconds_count{service="order-service", status=~"5.."}[1m])) by (group)
/
sum(rate(http_server_requests_seconds_count{service="order-service"}[1m])) by (group)
# Estado do Circuit Breaker (valor 1 indica estado aberto)
resilience4j_circuitbreaker_state{name="inventory", state="open"}
Fonte: elaborado pelo autor.
4.2 Primeira execução: refutação da hipótese
A Listagem 4 apresenta a configuração de resiliência que estava vigente no order-service antes do experimento.
Listagem 4 – Configuração original do Resilience4j
resilience4j:
circuitbreaker:
instances:
inventory:
sliding-window-size: 100
failure-rate-threshold: 50
wait-duration-in-open-state: 30s
Fonte: elaborado pelo autor.
Só ao analisar essa configuração em retrospecto percebi que ela não definia limite de tempo para as chamadas remotas nem critério de classificação de chamadas lentas. O Circuit Breaker contabilizava apenas exceções, de modo que uma chamada concluída com sucesso após 2 segundos não era registrada como falha. A Tabela 1 apresenta as métricas que observei nos primeiros quatro minutos.
Tabela 1 – Métricas da primeira execução
| Métrica | Grupo de controle | Grupo canary | Referência | Resultado |
|---|---|---|---|---|
| Taxa de sucesso | 99,7% | 98,1% | ≥ 99,5% | Não atendido |
| Latência p99 | 410 ms | 2.380 ms | < 450 ms | Não atendido |
| Estado do Circuit Breaker | Fechado | Fechado | Abertura esperada | Não atendido |
| Ocupação do pool de threads (Tomcat) | 22% | 91% | — | Anomalia |
Fonte: dados ilustrativos elaborados pelo autor.
Ao analisar os rastros no Jaeger, identifiquei o mecanismo de propagação da falha. As chamadas lentas ao inventory-service mantinham ocupadas as threads do servidor Tomcat. Com menos threads disponíveis, mesmo as requisições não submetidas à latência passaram a aguardar em fila. Assim, uma degradação aplicada a apenas 10% das chamadas comprometeu o desempenho de praticamente todo o grupo canary.
A violação da condição de aborto relativa à latência p99 interrompeu o experimento automaticamente no quarto minuto. A remoção da latência no Toxiproxy levou menos de cinco segundos, e as métricas retornaram aos valores de referência em aproximadamente 40 segundos.
Não interpreto a refutação da hipótese como insucesso do experimento, mas como seu resultado mais informativo. Com impacto limitado a cerca de 0,5% das requisições durante quatro minutos, identificamos uma fragilidade que, em um incidente real envolvendo a degradação do inventory-service, poderia comprometer a totalidade da criação de pedidos.
4.3 Medidas corretivas
Para corrigir o problema, adotamos de forma combinada quatro padrões de resiliência descritos por Nygard (2018), implementados por meio da biblioteca Resilience4j (RESILIENCE4J, 2024). A Listagem 5 apresenta a configuração resultante.
Listagem 5 – Configuração revisada do Resilience4j
resilience4j:
circuitbreaker:
instances:
inventory:
sliding-window-size: 50
failure-rate-threshold: 50
slow-call-rate-threshold: 30
slow-call-duration-threshold: 500ms
wait-duration-in-open-state: 15s
permitted-number-of-calls-in-half-open-state: 5
timelimiter:
instances:
inventory:
timeout-duration: 800ms
bulkhead:
instances:
inventory:
max-concurrent-calls: 20
Fonte: elaborado pelo autor.
A Listagem 6 mostra como apliquei os padrões no código do serviço.
Listagem 6 – Aplicação dos padrões de resiliência no order-service
@CircuitBreaker(name = "inventory", fallbackMethod = "estoqueDoCache")
@TimeLimiter(name = "inventory")
@Bulkhead(name = "inventory", type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<Estoque> consultarEstoque(String produtoId) {
return CompletableFuture.supplyAsync(() -> inventoryClient.buscar(produtoId));
}
private CompletableFuture<Estoque> estoqueDoCache(String produtoId, Throwable ex) {
log.warn("Fallback de estoque acionado para {}: {}", produtoId, ex.getMessage());
return CompletableFuture.completedFuture(
estoqueCache.ultimoValorConhecido(produtoId).comFlagReconciliacao()
);
}
Fonte: elaborado pelo autor.
Cada padrão cumpre uma função específica:
-
Time Limiter: impõe limite de 800 ms para cada chamada ao
inventory-service, impedindo que threads permaneçam ocupadas indefinidamente. -
Bulkhead: isola as chamadas ao
inventory-serviceem um pool de threads dedicado, de modo que sua saturação não comprometa os demais fluxos doorder-service. - Circuit Breaker com limiar de chamadas lentas: passa a considerar chamadas acima de 500 ms no cálculo de abertura do circuito, interrompendo tentativas contra uma dependência degradada.
- Fallback: com o circuito aberto, o pedido é registrado com base no último valor de estoque conhecido no cache e marcado para reconciliação assíncrona. Essa foi uma decisão de negócio que tomamos em conjunto com a área de produto: consideramos preferível aceitar o pedido com pequeno risco de divergência de estoque a recusar a venda.
4.4 Segunda execução: confirmação da hipótese
Após implantarmos as correções, executei novamente a carta REDE-07 com os mesmos parâmetros. A Tabela 2 apresenta os resultados.
Tabela 2 – Métricas da segunda execução
| Métrica | Grupo de controle | Grupo canary | Referência | Resultado |
|---|---|---|---|---|
| Taxa de sucesso | 99,7% | 99,6% | ≥ 99,5% | Atendido |
| Latência p99 | 405 ms | 790 ms | < 800 ms (hipótese) | Atendido |
| Estado do Circuit Breaker | Fechado | Aberto após ~20 s | Abertura esperada | Atendido |
| Chamadas atendidas por fallback | 0% | ~9% | — | Conforme esperado |
| Ocupação do pool de threads (Tomcat) | 21% | 26% | — | Normal |
Fonte: dados ilustrativos elaborados pelo autor.
Desta vez, o experimento transcorreu durante os 10 minutos previstos sem violar nenhuma condição de aborto. Observei o Circuit Breaker alternar entre os estados aberto e semiaberto conforme o esperado, e a latência p99 manteve-se imediatamente abaixo do limite imposto pelo Time Limiter.
Faço, porém, uma ressalva: a latência p99 do grupo canary aumentou de aproximadamente 400 ms para 790 ms. A hipótese foi confirmada, mas o sistema não se tornou imune à falha; passou a degradar de forma controlada e previsível. Considero essa distinção central para a compreensão da resiliência, que não corresponde à ausência de falhas, mas à capacidade de manter o serviço em níveis aceitáveis durante sua ocorrência.
4.5 Incorporação ao processo contínuo
Com a hipótese confirmada, incorporei a carta REDE-07 à nossa suíte de experimentos automatizados, e ela passou a ser executada semanalmente no grupo canary. Dessa forma, eventuais regressões, como a remoção acidental do Time Limiter em uma refatoração futura, serão detectadas antes de se manifestarem em um incidente real. Com essa etapa, atendemos ao quarto princípio do Chaos Engineering, que recomenda a automação contínua dos experimentos.
5. Conclusão
A experiência relatada neste artigo me mostrou, na prática, que o Chaos Engineering cumpre a função de substituir suposições por evidências. Antes de executarmos a carta REDE-07, eu e minha equipe acreditávamos que o Circuit Breaker protegia o sistema contra a degradação do inventory-service. O experimento refutou essa crença e revelou um mecanismo de falha em cascata que nossos testes funcionais não teriam identificado.
Desse experimento, extraio as seguintes lições:
- A latência é mais danosa que a indisponibilidade. Um serviço indisponível falha rapidamente, enquanto um serviço lento consome recursos de forma silenciosa até comprometer os serviços que dele dependem.
- A resiliência resulta da combinação de padrões. No caso que analisei, o Circuit Breaker sem limite de tempo foi ineficaz contra chamadas lentas.
- Hipóteses refutadas são os resultados de maior valor. Experimentos que apenas confirmam o comportamento esperado produzem pouco conhecimento novo.
- A observabilidade é pré-requisito do experimento. Sem a capacidade de medir o estado estável, a injeção de falhas deixa de ser experimentação e passa a ser apenas uma fonte de instabilidade.
- A delimitação do Blast Radius viabiliza o aprendizado com baixo risco. Um impacto de aproximadamente 0,5% das requisições durante quatro minutos nos permitiu identificar uma falha com potencial de afetar a totalidade do fluxo de pedidos.
No plano organizacional, percebi que o formato de baralho reduziu a percepção da prática como atividade de auditoria e favoreceu a participação conjunta das equipes de desenvolvimento e operações. Esse efeito reforçou, em nossa equipe, três fundamentos da cultura DevOps: a responsabilidade compartilhada, pois quem desenvolve o código passou a participar da análise de como ele falha em produção; o ciclo de retorno rápido, pois passamos a descobrir falhas em sessões controladas, e não durante plantões; e a melhoria contínua, pois cada hipótese refutada gera uma correção, e cada correção passa a ser verificada por um experimento automatizado.
Para quem pretende iniciar essa prática, recomendo uma abordagem incremental: selecionar uma única dependência crítica, formular uma hipótese no padrão "Se... então... porque...", delimitar um Blast Radius reduzido, definir condições de aborto objetivas e conduzir o primeiro experimento em ambiente de homologação. Como próximos passos, pretendo estender a análise a cartas de maior severidade, como a perda de uma zona de disponibilidade, e avaliar quantitativamente o efeito do programa de experimentos sobre indicadores como o tempo médio de recuperação (MTTR) e a frequência de incidentes.
Referências
BASIRI, A. et al. Chaos Engineering. IEEE Software, v. 33, n. 3, p. 35-41, 2016.
BEYER, B. et al. Site Reliability Engineering: how Google runs production systems. Sebastopol: O'Reilly Media, 2016.
NYGARD, M. T. Release It!: design and deploy production-ready software. 2. ed. Raleigh: Pragmatic Bookshelf, 2018.
PRINCIPLES OF CHAOS ENGINEERING. Principles of Chaos Engineering. 2019. Disponível em: https://principlesofchaos.org/. Acesso em: 15 out. 2026.
RESILIENCE4J. Resilience4j documentation. 2024. Disponível em: https://resilience4j.readme.io/. Acesso em: 15 out. 2026.
ROSENTHAL, C.; JONES, N. Chaos Engineering: system resiliency in practice. Sebastopol: O'Reilly Media, 2020.
SHOPIFY. Toxiproxy. 2024. Disponível em: https://github.com/Shopify/toxiproxy. Acesso em: 15 out. 2026.
Top comments (0)