TL;DR
- Load testing: Medir rendimiento del sistema bajo tráfico esperado
- Objetivo: Verificar que aplicación maneja cargas normales y pico
- Métricas clave: Tiempo de respuesta (p95), throughput, tasa de error
- Herramientas populares: k6 (moderno), JMeter (GUI), Gatling (Scala)
- Mejor práctica: Testea en ambientes production-like con datos realistas
- Cuándo ejecutar: Antes de releases, después de cambios mayores, regularmente en CI/CD
Tiempo de lectura: 12 minutos
Load testing asegura que tu aplicación puede manejar tráfico real. Sin él, descubres problemas de rendimiento por usuarios enojados — o peor, durante un momento crítico del negocio.
¿Qué es Load Testing?
Load testing mide cómo un sistema se desempeña bajo tráfico esperado de usuarios. Simula muchos usuarios concurrentes haciendo requests para verificar que la aplicación maneja la carga sin ralentizarse o fallar.
Tráfico normal: 100 users/min → Tiempo respuesta: 200ms ✓
Tráfico pico: 500 users/min → Tiempo respuesta: 350ms ✓
Sobre capacidad: 1000 users/min → Tiempo respuesta: 5000ms ✗
Load testing responde: “¿Puede nuestro sistema manejar el tráfico esperado?”
Por qué Importa Load Testing
1. Problemas de Rendimiento Son Costosos
Aplicaciones lentas cuestan dinero:
| Tiempo Respuesta | Impacto |
|---|---|
| Bajo 1 segundo | Usuarios permanecen engaged |
| 1-3 segundos | 40% abandonan |
| 3+ segundos | 70%+ abandonan |
| 10+ segundos | Usuarios raramente regresan |
Cada 100ms de latencia puede reducir conversión en 1%.
2. Fallos en Production Son Peores
Encontrar problemas en production significa:
- Pérdida de ingresos durante caídas
- Daño a reputación
- Fixes de emergencia bajo presión
- Potencial pérdida de datos
Load testing encuentra estos problemas antes que los usuarios.
3. El Tráfico Es Impredecible
Patrones de tráfico real varían:
Lunes 9am: Pico por horas laborales
Viernes 5pm: Caída cuando salen del trabajo
Black Friday: 10x tráfico normal
Momento viral: 100x tráfico normal (si tienes suerte)
Load testing te prepara para picos.
Tipos de Performance Testing
Load Testing (Carga)
Testea niveles de tráfico esperados:
// k6 load test - tráfico esperado
export const options = {
stages: [
{ duration: '5m', target: 100 }, // Rampa subida
{ duration: '10m', target: 100 }, // Estado estable
{ duration: '5m', target: 0 }, // Rampa bajada
],
};
Objetivo: Verificar operación normal.
Stress Testing (Estrés)
Presiona más allá de límites esperados:
// k6 stress test - encontrar punto de quiebre
export const options = {
stages: [
{ duration: '2m', target: 100 },
{ duration: '5m', target: 200 },
{ duration: '5m', target: 400 },
{ duration: '5m', target: 800 }, // Más allá de lo normal
{ duration: '2m', target: 0 },
],
};
Objetivo: Encontrar capacidad máxima y puntos de quiebre.
Spike Testing (Pico)
Testea aumentos súbitos de tráfico:
// k6 spike test - aumento súbito
export const options = {
stages: [
{ duration: '1m', target: 50 },
{ duration: '30s', target: 500 }, // Pico súbito
{ duration: '2m', target: 500 },
{ duration: '30s', target: 50 }, // Regreso
],
};
Objetivo: Verificar que sistema maneja cambios súbitos.
Soak Testing (Remojo)
Testea rendimiento durante períodos extendidos:
// k6 soak test - duración extendida
export const options = {
stages: [
{ duration: '5m', target: 100 },
{ duration: '8h', target: 100 }, // 8 horas
{ duration: '5m', target: 0 },
],
};
Objetivo: Encontrar memory leaks y degradación con el tiempo.
Métricas Clave a Rastrear
Tiempo de Respuesta
Cuánto tardan los requests en completarse:
p50 (mediana): 200ms - Mitad de requests más rápidos
p95: 500ms - 95% de requests más rápidos
p99: 1200ms - 99% de requests más rápidos
Max: 5000ms - Request más lento
Enfócate en p95/p99 — muestran peor experiencia de usuario.
Throughput
Requests procesados por unidad de tiempo:
Requests/segundo: 150 req/s
Transacciones/segundo: 30 tx/s
Transferencia datos: 15 MB/s
Mayor throughput significa más capacidad.
Tasa de Error
Porcentaje de requests fallidos:
Requests exitosos: 9,850
Requests fallidos: 150
Tasa error: 1.5% ← Muy alto para production
Meta: Bajo 1% tasa error, idealmente bajo 0.1%.
Uso de Recursos
Métricas del lado servidor:
CPU: 75% promedio, 95% pico
Memoria: 4GB / 8GB (50%)
Disk I/O: 200 IOPS
Red: 500 Mbps
Vigila cuellos de botella acercándose a límites.
Tu Primer Load Test
k6 (JavaScript)
// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 50, // 50 usuarios virtuales
duration: '5m', // Correr 5 minutos
thresholds: {
http_req_duration: ['p(95)<500'], // 95% bajo 500ms
http_req_failed: ['rate<0.01'], // Menos de 1% errores
},
};
export default function () {
// Test homepage
const homeResponse = http.get('https://example.com/');
check(homeResponse, {
'homepage status is 200': (r) => r.status === 200,
'homepage loads fast': (r) => r.timings.duration < 500,
});
// Simular tiempo de pensamiento
sleep(1);
// Test API endpoint
const apiResponse = http.get('https://example.com/api/products');
check(apiResponse, {
'api status is 200': (r) => r.status === 200,
'api returns data': (r) => JSON.parse(r.body).length > 0,
});
sleep(2);
}
Ejecutar con: k6 run load-test.js
JMeter
JMeter usa configuración XML, típicamente creada via GUI:
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan>
<hashTree>
<ThreadGroup>
<stringProp name="ThreadGroup.num_threads">50</stringProp>
<stringProp name="ThreadGroup.ramp_time">30</stringProp>
<stringProp name="ThreadGroup.duration">300</stringProp>
<HTTPSamplerProxy>
<stringProp name="HTTPSampler.domain">example.com</stringProp>
<stringProp name="HTTPSampler.path">/api/products</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
</HTTPSamplerProxy>
</ThreadGroup>
</hashTree>
</jmeterTestPlan>
Ejecutar con: jmeter -n -t test.jmx -l results.jtl
Locust (Python)
# locustfile.py
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
wait_time = between(1, 3) # Tiempo de pensamiento
@task(3) # Mayor peso
def view_homepage(self):
self.client.get("/")
@task(2)
def view_products(self):
self.client.get("/api/products")
@task(1)
def view_product_detail(self):
self.client.get("/api/products/1")
Ejecutar con: locust -f locustfile.py --host=https://example.com
Mejores Prácticas
1. Testea en Ambientes Production-Like
El ambiente importa:
❌ Testing en localhost con base de 1GB
✓ Testing en staging con datos tamaño production
Resultados de localhost no predicen rendimiento en production
Iguala:
- Especificaciones de servidores
- Tamaño de base de datos
- Configuración de red
- Integraciones third-party
2. Usa Datos de Test Realistas
// Malo: Siempre mismo request
http.get('/api/users/1');
// Bueno: Requests variados, realistas
const userId = Math.floor(Math.random() * 10000) + 1;
http.get(`/api/users/${userId}`);
Varía parámetros para tocar diferentes code paths y comportamiento de caché.
3. Simula Comportamiento Real de Usuario
Usuarios no hacen click tan rápido como scripts:
export default function () {
http.get('/');
sleep(2); // Tiempo pensamiento: leyendo homepage
http.get('/products');
sleep(3); // Tiempo pensamiento: viendo productos
http.post('/cart', { productId: 123 });
sleep(1); // Acción rápida
}
Incluye delays realistas entre acciones.
4. Define Criterios Pass/Fail Claros
Establece umbrales antes de testear:
export const options = {
thresholds: {
http_req_duration: ['p(95)<500', 'p(99)<1000'],
http_req_failed: ['rate<0.01'],
http_reqs: ['rate>100'], // Throughput mínimo
},
};
Tests deben pasar o fallar automáticamente.
5. Testea Regularmente
Load testing no debe ser evento único:
# GitHub Actions - load test semanal
on:
schedule:
- cron: '0 2 * * 0' # Cada domingo a las 2am
jobs:
load-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: k6 run tests/load-test.js
Detecta regresiones antes de que lleguen a production.
Comparación de Herramientas
| Herramienta | Lenguaje | Mejor Para | Curva Aprendizaje |
|---|---|---|---|
| k6 | JavaScript | Developers, CI/CD | Baja |
| JMeter | Java/XML | Equipos QA, GUI | Media |
| Gatling | Scala | Alto rendimiento | Media |
| Locust | Python | Equipos Python | Baja |
| Artillery | JavaScript | Apps serverless | Baja |
Eligiendo Herramienta
Elige k6 si:
- Developers escriben tests
- Necesitas integración CI/CD
- Prefieres código sobre GUI
Elige JMeter si:
- Equipo QA escribe tests
- Necesitas diseño visual de tests
- Necesitas ecosistema extenso de plugins
Elige Gatling si:
- Necesitas alto rendimiento
- Ambiente Scala/JVM
- Reportes HTML detallados
Interpretando Resultados
Resultados Saludables
✓ http_req_duration..........: avg=180ms p95=320ms p99=450ms
✓ http_req_failed............: 0.02%
✓ http_reqs..................: 15000 (250/s)
✓ vus........................: 50
Tiempos de respuesta bajos, mínimos errores, throughput consistente.
Indicadores de Problemas
✗ http_req_duration..........: avg=2500ms p95=8000ms p99=15000ms
✗ http_req_failed............: 15%
http_reqs..................: 3000 (50/s)
vus........................: 50
Banderas rojas:
- Altos tiempos de respuesta (especialmente p95/p99)
- Tasa error arriba de 1%
- Throughput cae bajo carga
- Alto uso de recursos
Encontrando Cuellos de Botella
Cuando tests fallan, investiga:
- Código aplicación — Queries lentos, algoritmos ineficientes
- Base de datos — Optimización queries, índices, connection pooling
- Infraestructura — Límites CPU/memoria, ancho de banda red
- Third parties — APIs externos lentos, rate limits
// Agrega logging detallado para identificar cuellos de botella
const response = http.get('/api/users');
console.log(`DNS: ${response.timings.blocked}ms`);
console.log(`Connect: ${response.timings.connecting}ms`);
console.log(`TLS: ${response.timings.tls_handshaking}ms`);
console.log(`Waiting: ${response.timings.waiting}ms`);
console.log(`Receiving: ${response.timings.receiving}ms`);
FAQ
¿Qué es load testing?
Load testing mide cómo un sistema se desempeña bajo tráfico esperado de usuarios. Simula muchos usuarios concurrentes haciendo requests simultáneamente para verificar que la aplicación maneja cargas normales y pico sin degradación de rendimiento. A diferencia de testing funcional que verifica si features funcionan, load testing verifica si features funcionan bajo condiciones de tráfico realistas. El objetivo es responder: “¿Puede nuestro sistema manejar el número esperado de usuarios?”
¿Cuál es la diferencia entre load testing y stress testing?
Load testing simula niveles de tráfico esperados para verificar operación normal. Stress testing intencionalmente excede límites esperados para encontrar puntos de quiebre. Piensa en load testing como “¿podemos manejar tráfico normal?” y stress testing como “¿cuándo nos quebramos?” Load testing usa números realistas de usuarios; stress testing presiona hasta que el sistema falla. Ambos son valiosos — load testing para validación, stress testing para planificación de capacidad.
¿Qué métricas debo rastrear en load testing?
Rastrea estas métricas clave: Percentiles de tiempo de respuesta (p50, p95, p99) muestran cómo usuarios experimentan el rendimiento — p95 significa 95% de requests son más rápidos que este valor. Throughput (requests por segundo) muestra capacidad. Tasa de error (porcentaje de requests fallidos) debe mantenerse bajo 1%. Uso de recursos (CPU, memoria, disk I/O) revela cuellos de botella. Enfócate en p95 tiempo de respuesta como métrica principal — representa experiencia real del usuario mejor que promedios.
¿Qué herramientas se usan para load testing?
Herramientas populares de load testing incluyen k6 (basado en JavaScript, moderno, amigable para developers), JMeter (Java, basado en GUI, plugins extensivos), Gatling (Scala, alto rendimiento), y Locust (basado en Python, fácil de aprender). k6 es ideal para developers que quieren tests como código en CI/CD. JMeter sirve a equipos QA que prefieren diseño visual de tests. Elige basándote en skills del equipo y necesidades de integración.
Ver También
- k6 vs JMeter - Comparación herramientas load testing
- JMeter vs Gatling - Herramientas performance testing
- JMeter Tutorial - Comenzando con JMeter
- Performance Testing Guide - Mejores prácticas
