← Volver al portal de guías
⚡ GUÍA TESTING DE PERFORMANCE
Performance moderno: load, stress, scalability, web vitals y observabilidad — alineado a ISO/IEC 25010
QA Shift-Left Methodology · by E-Gregorio
ISO/IEC 25010:2023 — Performance Efficiency Google Web Vitals (2024) SLO/SLI per SRE Workbook
Esta guía cubre cómo planificar, ejecutar e interpretar pruebas de performance modernas sobre arquitecturas web, API y batch — usando k6, Lighthouse CI y observabilidad. Va más allá de "JMeter al final del proyecto": integra performance dentro del pipeline (shift-left) con presupuestos de PR y SLOs continuos.
📋 Contenido

1. Modelo ISO/IEC 25010 — Performance Efficiency

ISO/IEC 25010:2023 define Performance Efficiency con tres sub-características. Toda prueba de performance debería poder mapearse a una de ellas:

Sub-característica Definición Cómo se prueba
Time behaviour Tiempos de respuesta, procesamiento y throughput cumplen lo esperado Load tests con métricas p50/p95/p99, stress tests para identificar el punto de quiebre
Resource utilization Cantidad y tipos de recursos usados son apropiados Monitoreo de CPU, memoria, I/O, red durante load tests; profile de aplicación
Capacity El sistema soporta el número máximo declarado de usuarios/transacciones Stress + scalability testing, identificar saturación

2. Tipos de pruebas de performance

Tipo Objetivo Forma de carga Cuándo aplicarlo
Smoke Validar que el sistema responde bajo carga mínima 1-5 VUs por pocos minutos Cada deploy; gate básico en CI
Load Comportamiento bajo carga esperada (p95 SLO cumple) Carga ramp-up hasta target sostenido Pre-release, semanal en staging
Stress Encontrar el punto de quiebre y observar degradación Carga creciente hasta que error rate > 1% o p95 > 2× SLO Antes de eventos esperados (Black Friday, lanzamiento)
Spike Resistencia a picos súbitos de tráfico 0 → 10× target en < 30s, sostener 1-5 min Sistemas con tráfico viral / lanzamientos / campañas
Soak / Endurance Detectar memory leaks, fugas de connections, degradación gradual Carga moderada sostenida por 4-24h Pre-release de versiones críticas
Scalability Verificar que añadir recursos mejora capacidad linealmente Load tests con 1, 2, 4, 8 instancias Validar autoscaling, capacity planning
Volume Performance bajo gran volumen de datos (no de tráfico) Carga normal con DB de tamaño realista (TB) Sistemas con datasets que crecen mucho
Frontend / Web Vitals Performance percibida por el usuario final (LCP, INP, CLS) Lighthouse, RUM (Real User Monitoring) Cada PR de UI; continuo en producción

3. Métricas core

3.1 Latencia: NUNCA promedio, SIEMPRE percentiles

⚠️ Regla fundamental: el promedio de latencia es una mentira estadística. Una API con p50=100ms, p95=200ms, p99=5s tiene "promedio" engañosamente bajo, pero el 1% de tus usuarios tiene una experiencia terrible. Usar siempre p50, p95, p99 (y p99.9 para sistemas críticos).
Métrica Qué mide Target típico (web)
p50 (mediana)50% de requests más rápidos que esto< 200ms
p9595% de requests más rápidos que esto< 1000ms
p9999% de requests — la cola "lenta"< 2000ms
p99.9Solo sistemas críticos — la cola extremaSLO específico
Tail ratiop99 / p50 — qué tan estable es el sistema< 10×

3.2 Throughput, error rate, saturation

Métrica Definición Cómo medirla
RPS / TPSRequests / transactions per secondk6 http_reqs rate, APM
Error rate% de respuestas con status ≥ 500 o errores aplicativosk6 http_req_failed, APM
Saturation (USE)% de uso del recurso más restringido (CPU, conn pool, queue)Prometheus, métricas de aplicación
ApdexÍndice de satisfacción 0-1 basado en thresholds T y 4TAPM (New Relic, Datadog)

3.3 Modelo USE (Brendan Gregg) para diagnóstico

Para cada recurso del sistema (CPU, memoria, disco, red), revisar:

4. Web Vitals modernos (Google, 2024)

Las Core Web Vitals de Google son el estándar de la industria para frontend performance. INP reemplazó a FID en marzo 2024, así que si tu material cita FID, está desactualizado.

Métrica Qué mide Bueno A mejorar Pobre
LCP
Largest Contentful Paint
Tiempo hasta renderizar el elemento más grande visible ≤ 2.5s ≤ 4.0s > 4.0s
INP
Interaction to Next Paint
Latencia de la interacción más lenta del usuario (reemplazó FID en mar 2024) ≤ 200ms ≤ 500ms > 500ms
CLS
Cumulative Layout Shift
Suma de cambios inesperados de layout ≤ 0.10 ≤ 0.25 > 0.25
FCP
First Contentful Paint
Cuándo aparece el primer texto/imagen (métrica complementaria) ≤ 1.8s ≤ 3.0s > 3.0s
TTFB
Time to First Byte
Tiempo del backend hasta el primer byte ≤ 0.8s ≤ 1.8s > 1.8s
📌 Lab vs Field: Lighthouse mide lab data (entorno sintético controlado). Para producción usá RUM (Real User Monitoring) — Chrome UX Report, Datadog RUM, Sentry. Las métricas pueden divergir hasta 30%.

5. SLI / SLO / Error Budget

Marco de Site Reliability Engineering (Google SRE Book). Convierte performance de "intentamos que sea rápido" a un compromiso medible:

Concepto Definición Ejemplo
SLI
Service Level Indicator
Métrica observable cuantitativa "% de requests con latencia < 500ms"
SLO
Service Level Objective
Objetivo interno sobre el SLI "99% de requests < 500ms en ventana de 28 días"
SLA
Service Level Agreement
Compromiso contractual con el cliente (con consecuencias) "95% de uptime mensual o 10% de crédito"
Error budget 1 - SLO. Cuánto error te podés permitir antes de gatear features. SLO 99.9% → budget = 0.1% = 43.2 min/mes de downtime
📌 Política operativa típica: mientras el error budget no se haya consumido, el equipo lanza features libremente. Si se consume, se pausan features y se prioriza estabilidad. Esto crea un balance objetivo entre velocidad y confiabilidad.

6. Perfiles de carga: Open vs Closed Model

Diferencia fundamental que la mayoría de herramientas viejas (JMeter clásico) ignoran:

Modelo Descripción Cuándo usarlo
Closed model
(Virtual Users / VUs)
N usuarios concurrentes, cada uno espera la respuesta antes de mandar la siguiente. Si el sistema se lentifica, los VUs envían menos. Apps internas con número fijo de usuarios concurrentes (CRM, ERP)
Open model
(Arrival rate)
X requests/segundo entran independientemente del estado del sistema. Si se lentifica, las queues crecen. APIs públicas, e-commerce, cualquier sistema con tráfico real (la mayoría)
⚠️ Coordinated omission: el closed model esconde el peor caso porque los VUs lentos automáticamente reducen la carga. Si tu sistema responde a usuarios que llegan según Poisson (la mayoría), usá open model (en k6: ramping-arrival-rate o constant-arrival-rate).

7. k6 — scripts y patrones recomendados

7.1 Load test básico con thresholds

// load-test.js — load test estándar con SLOs como thresholds import http from 'k6/http'; import { check, group } from 'k6'; export const options = { scenarios: { api_load: { executor: 'ramping-arrival-rate', // open model startRate: 10, timeUnit: '1s', preAllocatedVUs: 100, maxVUs: 500, stages: [ { target: 50, duration: '2m' }, // ramp-up { target: 200, duration: '5m' }, // load { target: 200, duration: '10m' }, // sustained { target: 0, duration: '2m' }, // ramp-down ], }, }, thresholds: { // SLOs como gates: el test FALLA si no se cumplen 'http_req_duration{name:GET /products}': ['p(95)<500', 'p(99)<1500'], 'http_req_duration{name:POST /orders}': ['p(95)<1000', 'p(99)<2500'], 'http_req_failed': ['rate<0.01'], // <1% errores 'checks': ['rate>0.99'], }, }; export default function () { group('browse-and-buy', () => { const r1 = http.get('https://api.example.com/products', { tags: { name: 'GET /products' } }); check(r1, { '200 ok': r => r.status === 200, 'has items': r => r.json('items.length') > 0 }); const r2 = http.post('https://api.example.com/orders', JSON.stringify({ productId: 'p1', qty: 1 }), { headers: { 'Content-Type': 'application/json' }, tags: { name: 'POST /orders' } }); check(r2, { '201 created': r => r.status === 201 }); }); }

7.2 Stress test — encontrar el punto de quiebre

export const options = { executor: 'ramping-arrival-rate', preAllocatedVUs: 100, maxVUs: 2000, stages: [ { target: 100, duration: '2m' }, { target: 500, duration: '5m' }, { target: 1000, duration: '5m' }, { target: 2000, duration: '5m' }, { target: 5000, duration: '5m' }, // hasta romper ], // sin thresholds — queremos VER dónde rompe };

7.3 Soak test — 8 horas para detectar memory leaks

export const options = { executor: 'constant-arrival-rate', rate: 100, timeUnit: '1s', duration: '8h', preAllocatedVUs: 200, thresholds: { 'http_req_duration': ['p(95)<500'], // debe mantenerse 8h 'http_req_failed': ['rate<0.005'], }, };

8. Lighthouse CI en pipeline

# lighthouserc.json { "ci": { "collect": { "url": ["https://staging.example.com/", "https://staging.example.com/products"], "numberOfRuns": 3 }, "assert": { "assertions": { "categories:performance": ["error", { "minScore": 0.85 }], "categories:accessibility": ["error", { "minScore": 0.95 }], "largest-contentful-paint": ["error", { "maxNumericValue": 2500 }], "interaction-to-next-paint": ["error", { "maxNumericValue": 200 }], "cumulative-layout-shift": ["error", { "maxNumericValue": 0.10 }] } }, "upload": { "target": "temporary-public-storage" } } }

9. Observabilidad y APM

Performance testing sin observabilidad es ciego. Stack mínimo recomendado:

CapaOpen sourceSaaSPara qué
MétricasPrometheus + GrafanaDatadog, New RelicRPS, latencia p95/p99, error rate, saturation
LogsLoki, OpenSearchDatadog Logs, SplunkErrores con contexto, correlación con traces
TracesJaeger, TempoHoneycomb, Datadog APMDistributed tracing, identificar bottleneck por servicio
RUM (frontend)Sentry self-hostedSentry, Datadog RUMWeb Vitals reales del usuario final
ProfilingPyroscope, ParcaDatadog Continuous ProfilerEncontrar hot paths en CPU/memoria
📌 Estándar emergente: OpenTelemetry (OTel). Define un único protocolo y SDK para métricas, logs y traces. Si vas a empezar de cero, hacelo OTel-native — te desacopla de cualquier vendor.

10. Performance shift-left: presupuestos en PR

El error más común es probar performance solo al final. La mejora 10× viene de romper el build cuando un PR introduce regresiones:

EtapaTestTriggerTiempo
PRLighthouse CI (frontend) + smoke k6 (backend)Cada commit< 5 min
Merge a mainLoad test corto (5 min)Auto post-merge< 10 min
Pre-releaseLoad + soak + spike completoManual o release branch30 min - 2 h
ProducciónSynthetic monitoring + RUMContinuo24/7

10.1 Workflow de presupuesto en PR (GitHub Actions)

name: Performance Budget on: [pull_request] jobs: perf: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Lighthouse CI run: | npm i -g @lhci/cli lhci autorun --config=./lighthouserc.json - name: k6 smoke uses: grafana/k6-action@v0.3.1 with: filename: tests/perf/smoke.js flags: --vus 10 --duration 2m

11. Plantilla — Performance Test Plan

# Performance Test Plan — <sistema> ## 1. Identificación - Sistema: … - Versión: … - Owner: … - Fecha: 2026-04-26 ## 2. Contexto y objetivos - Tráfico actual de pico: 1200 RPS - Crecimiento esperado en 6 meses: 3× - Objetivo del test: validar que escala a 4000 RPS con SLOs intactos ## 3. SLOs definidos | Endpoint | SLI | SLO | |---------------------------|-----------------------------|-----------------------| | GET /products | latencia p95 | < 300 ms | | POST /orders | latencia p95 | < 800 ms | | GET /search | latencia p95 | < 500 ms | | Toda la API | error rate | < 0.5% | | Toda la API | disponibilidad mensual | ≥ 99.9% | ## 4. Tipos de test a ejecutar | Test | Carga | Duración | Criterio éxito | |------------|-------------------|----------|----------------| | Smoke | 10 RPS | 2 min | 0 errores 5xx | | Load | 1500 RPS | 30 min | SLOs cumplidos | | Stress | 100 → 6000 RPS | 30 min | Identificar quiebre > 4000 | | Spike | 100 → 5000 en 30s | 10 min | Recovery < 60s | | Soak | 800 RPS | 8 h | Sin degradación, sin leaks | ## 5. Datos de prueba - 100k usuarios sintéticos pre-creados - Catálogo: copia del prod (anonimizado) - Datasets en CSV + parametrización en k6 ## 6. Entornos - Test ejecutado contra: staging-perf (idéntico a prod, escalado al 100%) - NO en prod salvo synthetic monitoring continuo ## 7. Observabilidad - Grafana dashboard "perf-test-suite" - APM: Datadog, capturando p50/p95/p99 por endpoint - Profiling: Continuous Profiler activo durante el test ## 8. Criterios de salida - [ ] Todos los SLOs cumplidos en el load test - [ ] Stress test identifica punto de quiebre y degradación es graceful - [ ] Spike test: recovery automático < 60s - [ ] Soak: memoria estable, sin leaks - [ ] Reporte HTML + dashboard linkeado en release notes

12. Anti-patterns

  • Reportar el promedio de latencia. Solo p50/p95/p99/p99.9 cuentan.
  • Probar en una máquina compartida con la aplicación. El generador de carga debe ser independiente.
  • Pruebas con datos vacíos. 10 productos en DB vs 10M es un mundo distinto. Volumen real (o sintético equivalente).
  • Closed model cuando deberías usar open model. Coordinated omission esconde problemas.
  • "Pasamos el load test" sin medir saturación de recursos. Si CPU está al 95% o pool de conexiones al límite, no escala.
  • Performance test al final del proyecto. Imposible corregir tarde — Shift-left con presupuestos en PR.
  • Lighthouse score como única métrica frontend. Es lab data — agregar RUM en producción.
  • No pre-calentar el sistema. JIT warm-up, cache fría, pool sin establecer → primeras métricas son irreales.
  • Test "sintético" muy distinto del tráfico real. Distribución de endpoints debe parecerse al pareto real.
  • No correlacionar resultados con observabilidad. Sin trace, no sabés POR QUÉ es lento.

📚 Referencias

QA Shift-Left Methodology — Framework operativo integrado por E-Gregorio
Guía Performance — referencia a estándares públicos: ISO/IEC 25010:2023 y Google Web Vitals 2024