Cinco etapas — modelo de falha, modelo de carga, cenário, observação, mitigação — percorridas em espiral sobre um serviço de exemplo, até reproduzir em bancada uma falha metaestável: o caso em que o sistema não volta sozinho depois que o gatilho já foi embora.
O rascunho lista cinco coisas: modelos de falha e injeção de falha, modelos de carga, chaos engineering, teste e observabilidade, e mecanismos de mitigação. Lidas soltas, parecem cinco assuntos. Lidas na ordem, são uma esteira: cada etapa produz a entrada da seguinte, e o conjunto é um método de ponta a ponta para medir como um serviço responde a estresse.
Uma falha e uma carga se combinam num cenário. O cenário roda contra um sistema instrumentado. A instrumentação produz números. Os números dizem se o serviço aguentou. Quando não aguentou, entra um mecanismo de mitigação — e é aí que a esteira deixa de ser linha reta, porque o mecanismo novo muda o sistema e obriga a refazer os cenários. É a espiral que ela aponta no final do rascunho.
A última linha do rascunho — "e vamos ver se conseguimos demonstrar uma falha metaestável" — é o que dá destino à esteira. Sem um alvo, montar bancada e injetar falha rende um catálogo de gráficos de latência. Com o alvo, cada etapa existe por um motivo: a falha metaestável é justamente o fenômeno que só aparece se as cinco etapas estiverem certas ao mesmo tempo. Carga fechada em vez de aberta, e ela não aparece. Sem medir depois do gatilho, e ela não aparece. Sem retry no cliente, e ela não aparece.
Essa é a pergunta que a esteira serve para responder. O que segue é cada etapa dela, com a ferramenta correspondente e a decisão que precisa ser tomada.
A professora sugere reusar uma taxonomia existente, e essa é a decisão certa: inventar classificação de falha é trabalho perdido e indefensável na banca. A referência canônica é Avizienis et al., que separa falta (a causa injetada), erro (o estado interno corrompido) e falha (o que o usuário vê). A distinção importa muito aqui, porque o TG mede a terceira em função da primeira.
O corte prático é o que ela já indicou: processo (crash, crash com restart, e pausa longa) e comunicação (perda de mensagem, delay, partição). Vale acrescentar a pausa longa — docker pause — porque é a mais cruel das três de processo: o processo não morre, então nada detecta, e todos os clientes ficam pendurados até o timeout. É o gatilho clássico de metaestabilidade.
Falha bizantina fica fora, e é bom dizer isso explicitamente no texto: é outro modelo de ameaça, exige consenso tolerante a bizantinos para fazer sentido, e dobraria o trabalho sem tocar na pergunta.
Esta é a etapa em que dá mais fácil de errar, e o erro é silencioso. Gerador de carga tem dois modos. No modo fechado — no k6, os executores constant-vus e ramping-vus — existem N usuários virtuais e cada um só manda o próximo pedido depois de receber a resposta do anterior. No modo aberto — constant-arrival-rate e ramping-arrival-rate — a taxa de chegada é fixa e independe de quanto o serviço demora.
Se o teste usa modo fechado, o próprio gerador se autolimita quando o serviço fica lento, o laço de realimentação nunca fecha, e a falha metaestável é matematicamente impossível de reproduzir. O trabalho pode rodar seis meses de experimento e concluir que o fenômeno não existe, por causa de uma linha de configuração. Schroeder, Wierman e Harchol-Balter escreveram um paper inteiro sobre esse tipo de erro.
Um segundo ponto de enquadramento: o timeout e o retry do cliente fazem parte do modelo de carga, não do sistema sob teste. É o cliente que decide desistir e pedir de novo, e é essa decisão que amplifica λ. Tratá-los como parâmetro de carga, e não como detalhe de implementação do serviço, é o que torna o experimento controlável.
A resposta é não improvisar. Um cenário precisa de três partes. Primeiro, uma hipótese de estado estável declarada em número antes de rodar — por exemplo "goodput acima de 95% de λ e p99 abaixo de 400 ms". É o que a literatura de chaos engineering coloca no centro do método: o experimento existe para tentar refutar uma afirmação, não para ver o que acontece.
Segundo, um desenho de experimento em vez de uma lista de anedotas. Os fatores são carga base como fração de μ, tipo de gatilho, configuração de timeout e retry do cliente, e mitigação ativa. O fatorial completo explode, então o caminho é varrer um fator por vez em volta de um ponto de referência, e registrar por que cada ponto foi escolhido. É exatamente o assunto do livro do Raj Jain, e é o que separa um capítulo de resultados de uma coleção de prints do Grafana.
Terceiro, e é o que quase nenhum teste de carga faz: o cenário tem que continuar medindo depois que o gatilho termina. Metaestabilidade só existe na janela pós-gatilho. Um teste que injeta pico, mede o pico e para, não consegue distinguir um sistema que se recupera de um que ficou preso — os dois têm o mesmo gráfico durante o pico.
O básico é conhecido: latência em percentis e não em média, taxa de erro, utilização e saturação de cada recurso. Sobre isso, duas medidas específicas fazem o trabalho.
A primeira é o fator de amplificação: pedidos que o servidor recebe divididos por pedidos que os clientes originaram. Em repouso vale 1. Quando o laço fecha, sobe. É a observação direta do mecanismo, e é o que transforma "o sistema caiu" em "o sistema caiu porque a carga triplicou sozinha".
A segunda é o tempo de recuperação após a remoção do gatilho. É a definição operacional de metaestabilidade: se o goodput não volta ao patamar anterior dentro de um múltiplo declarado da duração do gatilho, o sistema está no estado metaestável. Escolher esse múltiplo e defendê-lo é uma decisão de método que o TG precisa tomar cedo.
Vale registrar também que goodput se mede no cliente, não no servidor. Só o cliente sabe se ainda queria a resposta quando ela chegou. Um servidor a cem por cento de CPU produzindo respostas para pedidos abandonados reporta throughput excelente.
Os mecanismos estão descritos mais abaixo. O que a espiral acrescenta é o ponto interessante: medir um mecanismo isolado diz pouco. Já se sabe que backoff com jitter melhora as coisas. O que não está resolvido na literatura é o que acontece quando três mecanismos configurados de forma independente convivem no mesmo caminho de requisição.
Um exemplo concreto do problema: load shedding recusa trabalho rápido, produzindo erros rápidos; o circuit breaker do cliente lê erro rápido como falha e abre; com o breaker aberto, a carga cai e o shedding para de recusar; o breaker fecha, a carga volta de uma vez, e o shedding volta a recusar. O sistema oscila, e nenhum dos dois mecanismos está com defeito.
A professora escreve que a espiral aumenta a complexidade e exige mais teste. É verdade, e por isso ela precisa de um critério de parada declarado no escopo — proposta: duas voltas. Na primeira, um mecanismo medido antes e depois. Na segunda, dois mecanismos interagindo. Depois disso, congela e escreve.
Replicação, que ela cita junto com retry, merece uma nota crítica: ela protege contra falha de processo, mas também é amplificador sob sobrecarga. Requisição especulativa contra a segunda réplica, read repair e retry contra outro nó todos multiplicam λ justamente quando λ já é o problema. É um bom candidato a resultado do trabalho.
Antes das ferramentas, o alvo. Um servidor com capacidade fixa recebendo pedidos. Quando um pedido espera demais, o cliente desiste e pede de novo — e esse pedido novo entra na mesma fila. Suba a carga base para perto da capacidade, injete um pico e observe o que acontece depois que o pico termina.
trabalho útil entregue, % da capacidade
Com retry imediato e carga base alta, o pico termina e o goodput não volta. Troque para backoff ou retry budget e repita o experimento: o sistema afunda durante o pico, mas se recupera sozinho depois. Essa diferença é o objeto do trabalho.
Comece por uma distinção que sustenta o resto. Num sistema fechado, o número de clientes é fixo: se o servidor fica lento, cada cliente espera, e o trabalho novo diminui naturalmente. Num sistema aberto, a carga vem de fora e não te consulta — se o servidor fica lento, os pedidos continuam chegando no mesmo ritmo. Toda a web é sistema aberto. É a mesma distinção que reaparece na etapa 02 como uma escolha de configuração do k6, e é por isso que ela está aqui no começo.
Junte com capacidade. Um serviço processa até μ pedidos por segundo e recebe λ. Enquanto λ é menor que μ, a fila fica estável. Quando λ ultrapassa μ, a fila cresce sem limite e a latência explode. Isso é teoria de filas básica, e é a única matemática necessária para entender o resto.
O terceiro ingrediente é a diferença entre throughput e goodput. Throughput é quanto trabalho o servidor faz. Goodput é quanto desse trabalho serve para alguém. Um servidor pode estar cem por cento ocupado produzindo respostas que ninguém mais espera, porque o cliente já deu timeout e pediu de novo. Trabalho feito, jogado fora.
E aí vem o mecanismo. O cliente não recebe resposta a tempo e faz retry. Retry é uma feature de confiabilidade — existe justamente para tolerar falha transitória. Mas cada retry é um pedido novo, então o retry aumenta λ. Serviço lento leva a mais retries, que levam a λ maior, que leva a serviço mais lento. É realimentação positiva, e se auto-sustenta.
Ele está num estado localmente estável, do qual só sai com um empurrão externo. Daí o nome, emprestado da física. É exatamente por isso que reiniciar tudo funciona: você drena as filas e quebra o laço à força.
Cache é outro clássico: se um cache esvazia, todo o tráfego vai direto ao banco; o banco fica lento; como o banco está lento, o cache não consegue se repovoar; e o sistema fica preso com o cache frio indefinidamente. Tratamento de erro lento é outro — o caminho de exceção costuma ser mais caro que o caminho feliz, então mais erro gera mais lentidão, que gera mais erro. O próprio balanceador pode amplificar quando manda mais tráfego para o nó que respondeu rápido por acaso.
Backoff exponencial com jitter faz o cliente esperar cada vez mais entre tentativas, com aleatoriedade para não sincronizar todo mundo. Retry budget limita retries a uma fração do tráfego normal, tipicamente via token bucket, de modo que o retry nunca multiplique a carga além de um fator conhecido. Circuit breaker é uma máquina de estados no cliente que, após N falhas, para de tentar por um tempo e depois testa o terreno com poucos pedidos. Load shedding é o servidor recusar trabalho na entrada para proteger o que já aceitou. E propagação de deadline faz o pedido carregar consigo quanto tempo ainda resta, para ninguém gastar CPU num trabalho que já perdeu a validade.
O rascunho diz que provavelmente é preciso definir um sistema de exemplo, e que os componentes podem ficar mais complexos depois. A proposta é começar com o menor sistema que ainda tem um gargalo de verdade: quatro containers e um proxy, num docker compose, rodando num laptop.
Três razões. O pool fixo é a mais importante: um serviço com número limitado de workers tem capacidade conhecida, o que permite comparar o que a teoria de filas prevê com o que a bancada mede — sem isso, μ é uma incógnita e não há modelo para confrontar. O cache entra porque é o segundo amplificador clássico, e tê-lo desde o início evita reconstruir a bancada quando o TG quiser mostrar que o fenômeno não é exclusivo do retry. E o proxy separa a injeção de falha do código da aplicação, o que é o que torna o experimento honesto: o serviço não sabe que está sendo testado.
Nada de nuvem paga. O fenômeno reproduz em meia dúzia de containers num laptop, e cloud gerenciada troca tempo de pesquisa por tempo de configuração de IAM. Se depois for preciso mostrar orquestração e réplicas, k3s ou kind resolvem localmente.
O artigo do OSDI '22 publicou o código dos reprodutores que ele usa — aplicações pequenas que já exibem cada tipo de falha metaestável em ambiente controlado. Rodar isso primeiro responde a pergunta mais arriscada do TG — "eu consigo reproduzir o fenômeno?" — antes de qualquer linha de código próprio, e dá um ponto de referência para saber se a bancada nova está funcionando ou apenas quieta. Trocar por um serviço próprio depois é barato; descobrir em agosto que o fenômeno não reproduz, não é.
k6 para carga, com executor de taxa de chegada. Toxiproxy para falha de rede, controlado por API HTTP — o que importa aqui é que o cenário fica scriptável e portanto reprodutível. Docker para falha de processo, com kill, restart e pause. Prometheus e Grafana para métricas. Tudo com documentação boa e curva de aprendizado de dias, não de meses.
O e-mail pede exatamente isso: definir melhor as etapas necessárias e as desejadas. A separação abaixo é uma proposta para a reunião — a lista de cima é o que precisa existir para o trabalho fechar, e a de baixo é o que agrega se sobrar tempo. A intenção é ter um TG defensável mesmo no cenário em que nada da segunda lista acontece.
Vale destacar por que o item 1 da lista desejável é mais interessante do que parece. O trabalho de outubro de 2025 no arXiv aponta que modelos de fila padrão como o M/M/c simplesmente não exibem metaestabilidade — falta neles alguma coisa, e a candidata natural é justamente o laço de realimentação do retry, que um modelo com λ exógeno não tem como representar. Modelar antes de medir transforma a tese de "medimos e deu isso" em "o modelo prevê X, a bancada faz Y, e a diferença se explica por Z". É o que dá espinha dorsal a um trabalho experimental.
Proposta a validar na reunião, assumindo entrega no fim de 2027.
Toda vez que bater vontade de melhorar a aplicação, é sinal de fuga do experimento. O que mata TG de quem trabalha não é a bancada — é a escrita empurrada para o fim.
Bronson, Aghayev, Charapko e Zhu. Onde o termo nasce, a partir de anos operando sistemas em escala. Sete páginas, vale ler inteiro. Fecha dizendo que construir sistemas robustos a falhas metaestáveis desconhecidas segue um problema em aberto.
Huang et al. Estudo de 22 falhas em 11 organizações a partir de relatórios públicos de incidente; ao menos 4 dos 15 maiores outages da AWS na década se encaixam no padrão. Traz também aplicações que reproduzem cada tipo em ambiente controlado.
Marc Brooker, engenheiro principal da AWS. A leitura mais acessível das três, boa para fixar a intuição antes de encarar os papers.
Avizienis, Laprie, Randell e Landwehr. A taxonomia que a professora pede para reusar, e a fonte da distinção entre falta, erro e falha. É um artigo longo e de leitura seca, mas basta a parte de classificação de faltas para fundamentar o capítulo de modelo de falha.
Schroeder, Wierman e Harchol-Balter. Mostra que sistema aberto e sistema fechado se comportam de forma qualitativamente diferente sob a mesma carga nominal, e que escolher o modelo errado no gerador de carga inverte conclusões. É a referência que justifica a escolha de executor do k6 na etapa 02 — a decisão de método mais barata e mais fácil de errar de todo o TG.
Basiri et al., do time da Netflix. O artigo que formaliza a prática como experimento científico em vez de "quebrar coisas em produção": hipótese de estado estável declarada antes, variável independente controlada, e refutação. É o que responde à pergunta de como montar os cenários. Complementa os princípios, que são mais curtos e mais citáveis.
Teoria de filas e cadeias de Markov em tempo contínuo aplicadas ao fenômeno, com cálculo de tempos de recuperação. Traz uma observação que pode sustentar um TG inteiro: modelos de fila padrão como o M/M/c simplesmente não exibem metaestabilidade — descobrir o que falta neles é pergunta de pesquisa.
Aderaldo et al. Desenho experimental reutilizável: cenários especificados declarativamente para medir o impacto de desempenho de retry e circuit breaker sob carga e falha variadas. O mais próximo que existe de um molde pronto para a esteira deste TG.
Dois capítulos do livro de SRE do Google, livres na web. São a descrição mais concreta que existe de retry budget, load shedding e propagação de deadline em operação real, incluindo os números que eles usam. Não são artigo científico, mas são a fonte primária dos mecanismos que o TG vai medir.
Revisão sistemática de circuit breakers, retries, sagas, idempotência, bulkheads, backpressure e chaos testing entre 2014 e 2025. A conclusão — evidência fragmentada, resultados conflitantes, engenheiros sem base consolidada para escolher a tática certa — é o parágrafo de justificativa pronto.
Harchol-Balter, Performance Modeling and Design of Computer Systems, é a referência de teoria de filas aplicada a sistemas e aparece citada em quase todos esses papers. Raj Jain, The Art of Computer Systems Performance Analysis, é o clássico de desenho de experimento — importante porque metade dos trabalhos experimentais morre por medir errado, e é dele que sai o método da etapa 03. Nygard, Release It!, cobre o lado prático dos padrões de resiliência.
O rascunho já converge o escopo. O que falta decidir é o tamanho de cada etapa — e três dessas decisões mudam bastante o trabalho.