<p><strong>Meta Description:</strong> Aprenda testes de carga e stress: JMeter, k6, Gatling. Como simular milhares de usuários e identificar gargalos de performance.</p>

<hr>
<h2>Tipos de Teste de Carga</h2>

<h3>Load Testing</h3>

<p>Verifica comportamento sob carga esperada.</p>

<pre><code>Carga: 1000 usuários simultâneos
Duração: 30 minutos
Métrica: P95 &lt; 500ms
</code></pre>

<h3>Stress Testing</h3>

<p>Vai além dos limites normais.</p>

<pre><code>Carga: 1000 → 2000 → 5000 usuários
Objetivo: Encontrar ponto de quebra
</code></pre>

<h3>Spike Testing</h3>

<p>Picos súbitos de carga.</p>

<pre><code>Normal: 500 usuários
Spike: 5000 usuários em 5 segundos
Recovery: 500 usuários
</code></pre>

<h3>Soak Testing</h3>

<p>Carga sustentada por longo período.</p>

<pre><code>Carga: 1000 usuários
Duração: 8 horas
Objetivo: Memory leaks, degradação
</code></pre>

<hr>
<h2>k6 - Modern Load Testing</h2>

<h3>Instalação</h3>

<pre><code># macOS
brew install k6

<p># Linux<br>sudo apt install k6</p>

<p># Windows<br>choco install k6<br></code></pre></p>

<h3>Script Básico</h3>

<pre><code>// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

<p>export const options = {<br>  stages: [<br>    { duration: '2m', target: 100 },   // Ramp-up<br>    { duration: '5m', target: 100 },   // Steady<br>    { duration: '2m', target: 200 },   // Stress<br>    { duration: '5m', target: 200 },   // Steady<br>    { duration: '2m', target: 0 },     // Ramp-down<br>  ],<br>  thresholds: {<br>    http_req_duration: ['p(95)&lt;500&#039;],  // 95{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} &lt; 500ms<br>    http_req_failed: ['rate&lt;0.01&#039;],     // &lt; 1{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} errors<br>    checks: ['rate&gt;0.95'],              // &gt; 95{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} checks pass<br>  },<br>};</p>

<p>const BASE_URL = 'https://api.exemplo.com';</p>

<p>export default function () {<br>  // Login<br>  const loginRes = http.post(<code>${BASE_URL}/auth/login</code>, {<br>    email: 'user@example.com',<br>    password: 'password123',<br>  });</p>

<p>check(loginRes, {<br>    'login status 200': (r) =&gt; r.status === 200,<br>    'has token': (r) =&gt; r.json('token') !== undefined,<br>  });</p>

<p>const token = loginRes.json('token');</p>

<p>// Get products<br>  const productsRes = http.get(<code>${BASE_URL}/products</code>, {<br>    headers: { 'Authorization': <code>Bearer ${token}</code> },<br>  });</p>

<p>check(productsRes, {<br>    'products status 200': (r) =&gt; r.status === 200,<br>    'has products': (r) =&gt; r.json('items').length &gt; 0,<br>  });</p>

<p>sleep(1);<br>}<br></code></pre></p>

<h3>Cenários Complexos</h3>

<pre><code>// scenarios.js
import http from 'k6/http';
import { check, group } from 'k6/http';
import { Rate, Trend } from 'k6/metrics';

<p>const errorRate = new Rate('errors');<br>const apiLatency = new Trend('api_latency');</p>

<p>export const options = {<br>  scenarios: {<br>    // Smoke test<br>    smoke: {<br>      executor: 'constant-vus',<br>      vus: 10,<br>      duration: '1m',<br>      tags: { test_type: 'smoke' },<br>    },</p>

<p>// Load test<br>    load: {<br>      executor: 'ramping-vus',<br>      startVUs: 0,<br>      stages: [<br>        { duration: '2m', target: 100 },<br>        { duration: '5m', target: 100 },<br>        { duration: '2m', target: 0 },<br>      ],<br>      tags: { test_type: 'load' },<br>    },</p>

<p>// Stress test<br>    stress: {<br>      executor: 'ramping-arrival-rate',<br>      startRate: 1,<br>      timeUnit: '1s',<br>      preAllocatedVUs: 100,<br>      maxVUs: 500,<br>      stages: [<br>        { duration: '2m', target: 10 },<br>        { duration: '5m', target: 50 },<br>        { duration: '2m', target: 100 },<br>        { duration: '1m', target: 0 },<br>      ],<br>      tags: { test_type: 'stress' },<br>    },</p>

<p>// Spike test<br>    spike: {<br>      executor: 'ramping-vus',<br>      startVUs: 0,<br>      stages: [<br>        { duration: '30s', target: 100 },<br>        { duration: '1m', target: 1000 },  // Spike!<br>        { duration: '30s', target: 1000 },<br>        { duration: '2m', target: 0 },<br>      ],<br>      tags: { test_type: 'spike' },<br>    },<br>  },<br>};</p>

<p>export default function () {<br>  const res = http.get('https://api.exemplo.com/health');</p>

<p>errorRate.add(res.status !== 200);<br>  apiLatency.add(res.timings.duration);<br>}<br></code></pre></p>

<hr>
<h2>JMeter - Enterprise Load Testing</h2>

<h3>Instalação</h3>

<pre><code># Download
wget https://jmeter.apache.org/download_jmeter.cgi

<p># Run<br>./bin/jmeter.sh<br></code></pre></p>

<h3>Plano de Teste (GUI)</h3>

<pre><code>Test Plan
├── Thread Group (100 users, 10s ramp-up, loop 10)
│   ├── HTTP Request Defaults
│   │   └── Server: api.exemplo.com
│   │
│   ├── Once Only Controller
│   │   └── Login Request
│   │       └── POST /auth/login
│   │
│   ├── Recording Controller
│   │   └── GET /products
│   │   └── GET /products/{id}
│   │   └── POST /orders
│   │
│   └── Listeners
│       ├── Summary Report
│       ├── View Results Tree
│       ├── Aggregate Report
│       └── Graph Results
</code></pre>

<h3>JMeter CLI</h3>

<pre><code># Run non-GUI
jmeter -n -t test-plan.jmx -l results.jtl -e -o html-report

<p># With specific properties<br>jmeter -n -t api-test.jmx <br>  -Jthreads=100 <br>  -Jrampup=10 <br>  -Jduration=300 <br>  -l results.jtl<br></code></pre></p>

<h3>Distributed Testing</h3>

<pre><code># jmeter-server (on slave machines)
jmeter-server -Djava.rmi.server.hostname=192.168.1.100

<p># Run distributed<br>jmeter -n -t test.jmx <br>  -R192.168.1.100,192.168.1.101,192.168.1.102 <br>  -l results.jtl<br></code></pre></p>

<hr>
<h2>Gatling - Scala-based Load Testing</h2>

<h3>Instalação</h3>

<pre><code># Download
wget https://repo1.maven.org/maven2/io/gatling/highcharts/gatling-charts-highcharts-bundle/3.10.5/gatling-charts-highcharts-bundle-3.10.5.zip
unzip gatling-charts-highcharts-bundle-3.10.5.zip
</code></pre>

<h3>Script Scala</h3>

<pre><code>// src/test/scala/LoadSimulation.scala
package simulations

<p>import io.gatling.core.Predef._<br>import io.gatling.http.Predef._<br>import io.gatling.jdbc.Predef._<br>import io.gatling.core.structure.ScenarioBuilder</p>

<p>class ApiLoadSimulation extends Simulation {</p>

<p>val httpProtocol = http<br>    .baseUrl("https://api.exemplo.com")<br>    .acceptHeader("application/json")<br>    .contentTypeHeader("application/json")<br>    .disableCaching</p>

<p>val userFeeder = csv("users.csv").circular.random</p>

<p>val loginScenario: ScenarioBuilder = scenario("Login Flow")<br>    .feed(userFeeder)<br>    .exec(<br>      http("Login")<br>        .post("/auth/login")<br>        .body(StringBody(<br>          """{"email":"${email}","password":"${password}"}"""<br>        )).asJson<br>        .check(jsonPath("$.token").saveAs("authToken"))<br>    )<br>    .pause(1)<br>    .exec(<br>      http("Get Products")<br>        .get("/products")<br>        .header("Authorization", "Bearer ${authToken}")<br>        .check(status.is(200))<br>    )<br>    .pause(1)<br>    .exec(<br>      http("Create Order")<br>        .post("/orders")<br>        .header("Authorization", "Bearer ${authToken}")<br>        .body(StringBody(<br>          """{"productId":1,"quantity":2}"""<br>        )).asJson<br>        .check(status.is(201))<br>    )</p>

<p>setUp(<br>    loginScenario<br>      .inject(<br>        rampUsers(100).during(30.seconds),<br>        constantUsersPerSec(50).during(5.minutes),<br>        rampUsers(100).during(30.seconds)<br>      )<br>      .protocols(httpProtocol)<br>  )<br>  .assertions(<br>    global.responseTime.percentile(95).lt(500),<br>    global.successfulRequests.percent.gt(99)<br>  )<br>  .thresholds(<br>    http("Login").responseTime.percentile(99).lt(1000)<br>  )<br>}<br></code></pre></p>

<hr>
<h2>Interpreting Results</h2>

<h3>Key Metrics</h3>

<figure class="wp-block-table"><table>
<tr><th>Métrica</th><th>Significado</th><th>Target</th></tr>
<tr><td><strong>P95 Latency</strong></td><td>95{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} das requisições</td><td>&lt; 500ms</td></tr>
<tr><td><strong>P99 Latency</strong></td><td>99{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} das requisições</td><td>&lt; 1s</td></tr>
<tr><td><strong>Throughput</strong></td><td>Req/s</td><td>&gt; 1000</td></tr>
<tr><td><strong>Error Rate</strong></td><td>{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} falhas</td><td>&lt; 1{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td></tr>
<tr><td><strong>CPU</strong></td><td>Utilização</td><td>&lt; 80{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td></tr>
<tr><td><strong>Memory</strong></td><td>Utilização</td><td>&lt; 85{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td></tr>
</table></figure>

<h3>Finding Bottlenecks</h3>

<pre><code>// k6 com métricas customizadas
import { Trend } from 'k6/metrics';

<p>const dbLatency = new Trend('db_query_duration');<br>const externalLatency = new Trend('external_api_duration');</p>

<p>export default function () {<br>  const start = Date.now();<br>  // DB query<br>  const dbRes = http.get(<code>${BASE_URL}/db</code>);<br>  dbLatency.add(Date.now() - start);</p>

<p>// External API<br>  const extStart = Date.now();<br>  const extRes = http.get('https://external-api.com/data');<br>  externalLatency.add(Date.now() - extStart);<br>}<br></code></pre></p>

<hr>
<h2>Conclusão</h2>

<p>Testes de carga são essenciais para garantir performance. As chaves são:<br><ol><li><strong>Definir objetivos claros</strong> - SLAs e thresholds</li><br><li><strong>Simular realista</strong> - Dados e comportamento reais</li><br><li><strong>Monitorar infra</strong> - CPU, memória, rede</li><br><li><strong>Analisar resultados</strong> - P95, P99, throughput</li><br><li><strong>Testar regularmente</strong> - CI/CD integrado</li></ol></p>