Marcio Cunha

Como criar testes de carga realistas no k6 para sistemas web

Aprenda a simular picos complexos de tráfego usando k6 em pipelines de entrega contínua para descobrir gargalos antes que seus usuários percebam.

Marcio Cunha•4 min
Também disponível em:EnglishEspañol
Resumo
  • Testes de carga simulados no k6 reproduzem o comportamento real dos usuários através de cenários baseados em requisições HTTP programadas.
  • Pipelines de integração contínua executam scripts de performance automaticamente para barrar alterações que degradem o tempo de resposta.
  • Gargalos ocultos em bancos de dados e APIs aparecem claramente quando o sistema sofre estresse progressivo de requisições simultâneas.
  • Mapear thresholds toleráveis impede que falsos positivos quebrem o ciclo de entrega de software em ambientes de produção.
  • Ajustar a concorrência e o tempo de espera imita a navegação humana e evita quedas prematuras por bloqueio de segurança.

Por que testes sintéticos tradicionais falham na prática

Muitas equipes confiam em scripts simples que disparam mil requisições de uma vez só contra um servidor web, imaginando que isso representa um teste de carga real. Na prática, o comportamento humano é caótico: as pessoas entram no site gradualmente, clicam em botões em momentos diferentes, esperam as páginas carregarem e abandonam o carrinho no meio do processo. Quando simulamos apenas uma rajada cega de dados, coletamos métricas artificiais que não revelam como o sistema lida com o esgotamento progressivo de conexões ou com o uso excessivo de memória RAM.

Para resolver essa lacuna, precisamos de ferramentas que permitam escrever código legível para simular fluxos reais de navegação. É exatamente aqui que o k6, uma ferramenta moderna de testes de performance desenvolvida em JavaScript, se destaca na engenharia de software atual. Em vez de exigir interfaces gráficas pesadas, ele roda via linha de comando e permite versionar os testes junto com o código da aplicação, integrando-se perfeitamente aos fluxos de entrega contínua (o processo automatizado que leva código novo do computador do programador até o ar).

Simulando picos de tráfego complexos com k6 e cenários

Criar um teste de carga realista exige modelar o tráfego em fases, simulando a chegada de usuários pela manhã, o pico de acesso no horário de almoço e a calmaria da madrugada. No k6, isso é feito através de opções de execução avançadas que definem o número de usuários virtuais (as entidades que navegam pelo sistema de mentirinha) ao longo do tempo. Quando configuramos rampas de aceleração gradual, damos tempo para o banco de dados aquecer seus caches internos e para o balanceador de carga distribuir as conexões de forma orgânica.

Além de planejar as etapas de tráfego, precisamos garantir que o código do teste reflita jornadas reais de uso. Isso significa que um usuário simulado não deve apenas bater na página inicial; ele precisa fazer login, buscar um produto, adicionar ao carrinho e finalizar a compra. Para estruturar sistemas tolerantes a falhas na nuvem, você pode consultar o guia sobre como projetar arquiteturas resilientes que suportam variações bruscas de acesso sem derrubar os serviços essenciais.

Escrevendo o primeiro script de teste com k6

Vamos colocar a mão na massa com um exemplo prático de script escrito em JavaScript para o k6. Este código define uma rotina onde os usuários virtuais acessam uma página de API de forma contínua, simulando uma carga constante e medindo o tempo de resposta obtido. A estrutura utiliza funções nativas do k6 para verificar se o código de status HTTP retornado é o esperado, garantindo que o sistema não apenas responda rápido, mas que responda com sucesso.

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '30s', target: 20 },
    { duration: '1m', target: 50 },
    { duration: '10s', target: 0 },
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'],
  },
};

export default function () {
  const res = http.get('https://api.exemplo.com/produtos');
  check(res, {
    'status é 200': (r) => r.status === 200,
  });
  sleep(1);
}

Neste exemplo, o bloco de opções estabelece três momentos distintos: trinta segundos subindo até vinte usuários, um minuto mantendo cinquenta usuários ativos simultaneamente, e dez segundos descendo até zero. A propriedade thresholds funciona como um juiz automatizado que reprova o teste se noventa e cinco por cento das requisições demorarem mais de quinhentos milissegundos para responder. Essa automação é vital para garantir que a infraestrutura se mantenha estável antes de qualquer mudança chegar ao ambiente de produção.

Analisando gargalos e integrando testes ao pipeline

Executar testes de carga manualmente na máquina do desenvolvedor não garante que o sistema vai aguentar o tráfego real, pois os recursos locais de rede e hardware diferem drasticamente dos servidores em nuvem. A verdadeira maturidade operacional acontece quando integramos o k6 diretamente no pipeline de entrega contínua, como o GitHub Actions ou GitLab CI. Assim, toda vez que um desenvolvedor altera uma consulta ao banco de dados ou atualiza uma biblioteca, o sistema roda um teste rápido de performance para certificar que nenhuma regressão foi introduzida.

Durante essas execuções automatizadas, precisamos monitorar métricas vitais como o consumo de CPU, a saturação de memória e o tempo de espera nas filas de disco. Se a aplicação começa a engasgar sob carga moderada, o gargalo geralmente está em consultas SQL mal indexadas ou em bloqueios de concorrência. Para manter a estabilidade geral da infraestrutura corporativa, vale a pena conferir as recomendações de como gerenciar infraestrutura com Terraform para provisionar recursos elásticos que acompanham a demanda dos testes.

Considerações finais sobre testes de performance contínuos

Criar testes de carga realistas deixa de ser um evento isolado e passa a ser uma prática diária de engenharia quando incorporamos a simulação de picos de tráfego no ciclo de vida do software. Ferramentas como o k6 facilitam a transição de testes manuais e lentos para validações automatizadas rápidas e integradas ao código. Ao antecipar falhas de concorrência e gargalos de infraestrutura antes que eles cheguem aos clientes finais, as equipes ganham confiança para entregar novas funcionalidades com rapidez, segurança e alta disponibilidade operacional.