k6: testes de carga e stress test na VPS

    k6 é a ferramenta de load testing moderna que substituiu o JMeter — scripts em JavaScript, métricas detalhadas e integração com Grafana. Com k6 você descobre o limite real da sua VPS antes que os usuários descubram, identifica onde a latência aumenta sob carga e valida se um deploy melhorou ou piorou a performance.

    Instalar k6 e primeiro teste

    Instalação e script básico de load test:

    javascript
    # Instalar k6 no Ubuntu:
    sudo gpg -k
    sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg \
      --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
    echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" \
      | sudo tee /etc/apt/sources.list.d/k6.list
    sudo apt update && sudo apt install -y k6
    
    # Script básico — test.js:
    import http from 'k6/http'
    import { check, sleep } from 'k6'
    
    export const options = {
      vus: 50,          // 50 usuários virtuais simultâneos
      duration: '30s',  // por 30 segundos
    }
    
    export default function () {
      const res = http.get('https://api.seudominio.com.br/health')
      check(res, {
        'status 200': (r) => r.status === 200,
        'latência < 200ms': (r) => r.timings.duration < 200,
      })
      sleep(1)  // pausa de 1s entre requisições por VU
    }
    
    # Executar:
    k6 run test.js

    Cenários de carga: ramp-up, stress e spike

    Simular diferentes padrões de tráfego:

    javascript
    // scenarios.js — múltiplos cenários de carga
    
    export const options = {
      scenarios: {
        // Ramp-up gradual (simula crescimento normal):
        ramp_up: {
          executor: 'ramping-vus',
          startVUs: 0,
          stages: [
            { duration: '2m', target: 50 },   // subir para 50 VUs em 2 min
            { duration: '5m', target: 50 },   // manter 50 VUs por 5 min
            { duration: '2m', target: 0 },    // reduzir para 0
          ],
        },
    
        // Stress test (encontrar o ponto de quebra):
        stress: {
          executor: 'ramping-vus',
          stages: [
            { duration: '2m', target: 100 },
            { duration: '2m', target: 200 },
            { duration: '2m', target: 300 },  // aumentar até quebrar
            { duration: '2m', target: 0 },
          ],
        },
    
        // Spike test (pico súbito):
        spike: {
          executor: 'ramping-vus',
          stages: [
            { duration: '10s', target: 0 },
            { duration: '1m',  target: 500 }, // pico de 500 VUs de repente
            { duration: '3m',  target: 0 },
          ],
        },
      },
    
      thresholds: {
        http_req_duration: ['p(95)<500'],  // 95% das req < 500ms
        http_req_failed:   ['rate<0.01'],  // < 1% de falhas
      },
    }

    Testar fluxo completo de API autenticada

    Script realista com login, token e chamadas encadeadas:

    javascript
    // api-flow.js
    import http from 'k6/http'
    import { check, group } from 'k6'
    
    const BASE_URL = 'https://api.seudominio.com.br'
    
    export default function () {
      // 1. Login e obter token:
      group('Auth', () => {
        const loginRes = http.post(`${BASE_URL}/auth/login`, JSON.stringify({
          email: 'teste@runstack.com.br',
          senha: 'senha123',
        }), { headers: { 'Content-Type': 'application/json' } })
    
        check(loginRes, {
          'login 200': (r) => r.status === 200,
          'token presente': (r) => JSON.parse(r.body).token !== undefined,
        })
    
        const { token } = JSON.parse(loginRes.body)
        const headers = {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json',
        }
    
        // 2. Buscar lista de pedidos:
        group('Pedidos', () => {
          const pedidosRes = http.get(`${BASE_URL}/pedidos?page=1`, { headers })
          check(pedidosRes, {
            'pedidos 200': (r) => r.status === 200,
            'lista não vazia': (r) => JSON.parse(r.body).data.length > 0,
          })
        })
      })
    }

    Analisar métricas e interpretar resultados

    Entender o output do k6 e identificar problemas:

    bash
    # Output do k6 — métricas principais:
    # http_req_duration ............. p(90)=45ms p(95)=89ms p(99)=320ms
    # http_req_failed ............... 0.12% ✓ 988 ✗ 12
    # http_reqs ..................... 5000   83.3/s
    # vus_max ....................... 50
    
    # Interpretar:
    # p(95) > 500ms     → 5% dos usuários estão com má experiência
    # http_req_failed > 1% → aplicação começando a falhar sob carga
    # Latência p(95) crescendo → memory leak ou saturação de recursos
    
    # Exportar resultado como JSON para análise:
    k6 run --out json=resultado.json test.js
    
    # Integrar com Grafana via InfluxDB:
    k6 run --out influxdb=http://localhost:8086/k6 test.js
    
    # Verificar o que acontece no servidor durante o teste:
    # (em outro terminal, durante k6 run)
    watch -n 1 "ps aux | grep node | awk '{print $3, $4, $11}'"
    watch -n 1 "ss -s"
    htop

    Comparar antes e depois de uma otimização

    Metodologia para validar melhorias de performance:

    bash
    #!/bin/bash
    # compare-perf.sh — baseline vs otimizado
    
    echo "=== Baseline (antes da otimização) ==="
    k6 run --quiet --out json=/tmp/baseline.json \
      -e BASE_URL=https://api.seudominio.com.br test.js
    
    echo "=== Aplicar otimização (deploy nova versão) ==="
    # ... seu processo de deploy aqui
    
    echo "=== Após otimização ==="
    k6 run --quiet --out json=/tmp/otimizado.json \
      -e BASE_URL=https://api.seudominio.com.br test.js
    
    # Comparar p95 de latência:
    python3 << 'EOF'
    import json
    
    def p95(filename):
        with open(filename) as f:
            for line in f:
                data = json.loads(line)
                if data.get('type') == 'Point' and data['metric'] == 'http_req_duration':
                    pass  # simplificado — usar k6 summary direto
    
    baseline_p95 = 89    # ms — extrair do output
    otimizado_p95 = 45   # ms
    
    melhoria = (baseline_p95 - otimizado_p95) / baseline_p95 * 100
    print(f"Melhoria: {melhoria:.1f}% ({baseline_p95}ms → {otimizado_p95}ms)")
    EOF

    $ runstack deploy --plan starter

    Não quer configurar manualmente?

    Não quer configurar manualmente? Implante o VPS para APIs em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.

    Perguntas frequentes