Marcio Cunha

Como Simular Falhas e Latência em Requisições de Rede com Toxiproxy

Aprenda a injetar atrasos, quedas e instabilidades de rede de forma controlada nos seus testes automatizados usando o Toxiproxy, garantindo softwares mais resilientes.

Marcio Cunha12 min
Também disponível em:EnglishEspañol
Resumo
  • Testar sistemas em redes perfeitas esconde falhas críticas que só aparecem em produção.
  • O Toxiproxy atua como um proxy TCP intermediário simulando condições reais sem alterar o código da aplicação.
  • Ajustar latência e jitter permite validar o comportamento de timeouts e reconexões sob estresse.
  • Injetar perda de pacotes revela como o sistema lida com idempotência e perda de dados em trânsito.
  • Integrar a ferramenta em pipelines de integração contínua previne regressões de resiliência.

O Desafio Invisível da Instabilidade de Rede

Quando desenvolvemos aplicações modernas, costumamos testar tudo em ambientes controlados onde a internet funciona perfeitamente, sem atrasos e sem quedas. Na prática, a realidade dos usuários é completamente diferente, marcada por conexões instáveis, redes móveis oscilantes e servidores lentos do outro lado do mundo. Testar a resiliência do seu software diante desses cenários exige ferramentas específicas que consigan manipular o tráfego de dados. Sem simular essas falhas com antecedência, descobrimos os problemas apenas quando o sistema já está no ar, causando frustração nos clientes e chamadas de emergência de madrugada.

Para resolver esse dilema, engenheiros costumam recorrer a abordagens manuais como desconectar o cabo de rede ou limitar a velocidade no navegador, mas essas soluções são limitadas e difíceis de automatizar. É aqui que entra o conceito de proxy TCP, um servidor intermediário que fica entre a sua aplicação e o serviço externo, interceptando e manipulando todo o tráfego que passa por ele. Na prática, um proxy funciona como um porteiro rigoroso que pode decidir atrasar a entrega de uma mensagem, rasgar um pacote de dados no meio do caminho ou simplesmente fingir que o destinatário não está em casa. Essa manipulação cirúrgica do fluxo de rede é a chave para construir sistemas tolerantes a falhas.

Conhecendo o Toxiproxy e sua Arquitetura

Criado pela equipe do Shopify, o Toxiproxy é uma ferramenta de código aberto projetada especificamente para testar condições de rede adversas de maneira automatizada e programática. O projeto é dividido em duas partes principais: um servidor escrito em Go que executa as regras de manipulação de rede e uma API cliente disponível em várias linguagens que permite controlar esse servidor. Na prática, você configura o Toxiproxy para escutar em uma porta local e redirecionar o tráfego para o seu banco de dados ou API real, injetando as chamadas "toxinas" no meio do caminho. Isso significa que a sua aplicação continua apontando para um endereço local, sem saber que o tráfego está sendo sutilmente corrompido ou atrasado pelo meio.

A grande vantagem dessa arquitetura é o isolamento absoluto, pois nenhum código da sua aplicação precisa ser alterado para que os testes de caos aconteçam. Você não precisa injetar lógica de simulação de erro no seu código de produção, o que mantém o código limpo e focado estritamente na regra de negócio. Além disso, como o Toxiproxy roda facilmente como um contêiner Docker, ele se integra sem atrito a ambientes de integração contínua, onde os testes automatizados rodam a cada nova linha de código escrita pela equipe. Essa facilidade de configuração transforma testes de resiliência, que antes exigiam infraestruturas complexas de laboratório, em tarefas triviais que rodam na máquina de qualquer desenvolvedor.

Configurando o Ambiente e Criando o Primeiro Proxy

Para colocar a ferramenta em funcionamento, a forma mais rápida é utilizar o Docker para subir o servidor Toxiproxy junto com a CLI (interface de linha de comando) para gerenciar as regras. O comando básico para iniciar o servidor consiste em mapear a porta onde o proxy vai escutar e a porta da API de controle, permitindo que você envie comandos para criar as conexões virtuais. Na prática, você cria um 'toxicamente' chamado de 'proxy', definindo um nome amigável, o endereço de escuta local e o endereço do serviço real que você deseja atingir, como um banco de dados PostgreSQL ou um microsserviço de pagamentos. Uma vez criado, qualquer requisição feita para a porta local será intermediada pelo Toxiproxy antes de chegar ao destino final.

Podemos exemplificar essa configuração criando um proxy via linha de comando para um serviço fictício de API:

docker run --rm -d -p 8474:8474 -p 8080:8080 --name toxiproxy shopify/toxiproxy
toxiproxy-cli create -l 0.0.0.0:8080 -u api.exemplo.com:443 minha-api

Neste exemplo, o Toxiproxy agora está escutando na porta 8080 e repassando todo o tráfego para 'api.exemplo.com'. A aplicação cliente passa a fazer requisições para 'localhost:8080', permitindo que o desenvolvedor aplique modificações no tráfego em tempo de execução sem reiniciar nenhum serviço. Essa flexibilidade dinâmica é fundamental para testar como o sistema reage quando a rede degrada repentinamente durante o uso.

Injetando Latência e Jitter para Testar Timeouts

A latência é o atraso temporal que um pacote de dados leva para ir da origem ao destino, enquanto o 'jitter' representa a variação imprevisível nessa velocidade de entrega. Na prática, redes reais nunca são constantes; um pacote pode demorar 50 milissegundos em um momento e 400 milissegundos logo em seguida devido a congestionamentos na rota. Para simular esse comportamento no Toxiproxy, adicionamos uma toxina do tipo 'latency' ao nosso proxy previamente configurado, especificando o tempo base de atraso e a variação aceitável. Isso força a aplicação a lidar com esperas prolongadas e ajuda a validar se os limites de tempo limite, conhecidos como timeouts, estão configurados com margens realistas e seguras.

Veja como adicionar latência usando a interface de linha de comando da ferramenta:

toxiproxy-cli toxic add -t latency -a latency=1000 -a jitter=200 minha-api

Na prática, esse comando adiciona um atraso de um segundo com uma variação de duzentos milissegundos em todas as requisições que passam pelo proxy. Quando a sua aplicação tenta falar com a API, ela percebe que a resposta demorou muito mais do que o habitual, acionando os mecanismos internos de proteção. Se o seu sistema não possuir timeouts bem definidos, as threads de processamento ficarão travadas esperando a resposta, esgotando os recursos do servidor e derrubando a aplicação inteira em cascata. O Toxiproxy torna visíveis essas falhas de arquitetura antes que elas cheguem ao ambiente de produção.

Simulando Perda de Pacotes e Quedas de Conexão

Além da lentidão, as redes sofrem com perda de pacotes, onde pedaços inteiros de informação se perdem no meio do caminho devido a interferências físicas ou falhas de roteamento. Quando isso acontece, o protocolo de transporte precisa reenviar os dados perdidos, gerando retransmissões que degradam drasticamente a performance geral do sistema distribuído. No Toxiproxy, podemos simular esse cenário desastroso utilizando a toxina de perda de pacotes, definindo uma porcentagem exata de dados que serão descartados aleatoriamente pelo proxy. Essa simulação revela de imediato se o código da sua aplicação sabe lidar com falhas transitórias ou se ele quebra ao primeiro sinal de instabilidade na rede.

Outra toxina extremamente útil para testes de caos é a 'timeout', que fecha conexões abruptamente após um determinado período de inatividade ou de forma programada. Isso permite verificar se o sistema possui políticas robustas de repetição de requisições, conhecidas como retries, combinadas com estratégias de espera progressiva, o 'exponential backoff'. Na prática, se a conexão cai no meio de um pagamento, a aplicação não deve simplesmente duplicar a cobrança, mas sim verificar o estado da transação com segurança antes de tentar novamente. O uso combinado dessas toxinas garante que o software mantenha a integridade dos dados mesmo operando sobre uma infraestrutura de rede completamente caótica e hostil.

Automatizando Testes de Resiliência em Pipelines de CI/CD

Testar a rede manualmente é útil durante o desenvolvimento inicial, mas a verdadeira maturidade operacional vem quando esses testes de caos rodam de forma automatizada no pipeline de integração contínua. Em ferramentas como GitHub Actions ou GitLab CI, você pode iniciar o serviço do Toxiproxy em segundo plano durante a execução da suíte de testes de integração e ponta a ponta. A suíte de testes pode então ligar e desligar diferentes toxinas programaticamente através da API REST do Toxiproxy, validando cenários específicos de falha para cada caso de teste executado. Dessa forma, qualquer alteração no código que remova um tratamento de erro de rede ou reduza o timeout de forma imprudente é imediatamente barrada antes de chegar ao repositório principal.

Essa abordagem automatizada transforma a resiliência de rede em um requisito mensurável e testável, exatamente como fazemos com os testes unitários tradicionais. Os desenvolvedores ganham confiança para refatorar códigos legados de integração sabendo que a rede instável não vai surpreendê-los na primeira sexta-feira à tarde em produção. Além disso, documentar esses cenários de teste ajuda a equipe a compreender os limites operacionais reais do sistema, facilitando o planejamento de capacidade e a definição de acordos de nível de serviço, os famosos SLAs. A engenharia moderna exige que assumamos que a falha é inevitável, e ferramentas como o Toxiproxy nos dão o poder de ensaiar essa falha em um ambiente seguro.

Considerações Finais sobre Engenharia de Resiliência

Simular falhas e latência em requisições de rede deixou de ser um luxo restrito a grandes empresas de tecnologia e passou a ser uma necessidade básica para qualquer sistema distribuído moderno. Ao longo deste artigo, vimos como o Toxiproxy atua como um intermediário poderoso e transparente, permitindo injetar atrasos, jitter e perda de pacotes sem modificar uma única linha do código da aplicação. Essa prática revela vulnerabilidades ocultas, como timeouts mal configurados e falta de idempotência, que costumam causar grandes dores de cabeça em ambientes de produção. Adotar essa mentalidade de testes de caos garante que a sua aplicação continue firme e estável, mesmo quando o mundo ao redor enfrenta uma tempestade digital.

Em última análise, a estabilidade de um sistema não depende apenas da robustez do código isolado, mas de como ele interage com o caos inerente ao mundo real. Integrar simulações de rede aos testes automatizados eleva o patamar técnico da equipe, mudando o foco de apagar incêndios para prevenir falhas de forma sistemática e previsível. Com ferramentas acessíveis e flexíveis, qualquer engenheiro pode começar a testar os limites da sua infraestrutura hoje mesmo, construindo softwares verdadeiramente preparados para o inesperado. A resiliência deixa de ser uma promessa abstrata e se torna um atributo de engenharia validado a cada ciclo de desenvolvimento.