TL;DR
- Valida políticas de auto-scaling con pruebas de carga reales antes de producción—K6 para equipos JavaScript/TypeScript, Locust para equipos Python
- Usa Terraform para provisionar infraestructura efímera de pruebas de carga: levanta, prueba, destruye—paga solo por la duración del test
- Prueba tres escenarios como mínimo: carga sostenida (baseline), pico de carga (disparo de auto-scaling) y recuperación (comportamiento de scale-down)
Ideal para: Equipos con infraestructura auto-escalable que necesitan validar políticas de scaling y entender límites de capacidad No recomendado si: Ejecutas infraestructura de capacidad fija sin auto-scaling (enfócate en planificación de capacidad) Tiempo de lectura: 14 minutos
Las políticas de auto-scaling que funcionan en teoría frecuentemente fallan bajo carga real. Una política que se activa al 70% de CPU puede escalar muy lentamente, dejando usuarios esperando. O puede escalar muy agresivamente, desperdiciando presupuesto. La única forma de saber que tu infraestructura maneja carga correctamente es probarla.
Para testing de infraestructura relacionado, consulta Estrategias de Testing de Terraform y Testing de Configuración de Red.
Enfoques Asistidos por IA
Las herramientas de IA destacan generando scripts de pruebas de carga y analizando patrones de rendimiento.
Generando escenarios de prueba de carga con K6:
Escribe un script de prueba de carga K6 que valide comportamiento de auto-scaling:
Aplicación objetivo: API REST con endpoints /api/users, /api/orders
Infraestructura: AWS ALB + Auto Scaling Group (min: 2, max: 10, CPU objetivo: 70%)
Incluye tres etapas de prueba:
1. Calentamiento: Incremento gradual a 100 VUs en 2 minutos
2. Carga sostenida: Mantener 500 VUs por 10 minutos (debe disparar scale-up)
3. Pico: Ráfaga a 2000 VUs por 1 minuto, luego volver a 500
4. Enfriamiento: Disminuir gradualmente a 0 en 5 minutos (debe disparar scale-down)
Agrega thresholds para:
- Tiempo de respuesta p95 < 500ms
- Tasa de error < 1%
- Métricas personalizadas para rastrear eventos de scaling
Incluye integración con CloudWatch para correlacionar carga con conteo de instancias ASG.
Analizando comportamiento de auto-scaling:
Analiza estos resultados de prueba de carga y métricas de auto-scaling:
Timeline de prueba de carga:
- 0-2min: Rampa a 100 VUs, p95=120ms
- 2-12min: 500 VUs sostenidos, p95 comenzó en 150ms, creció a 800ms al minuto 8
- ASG escaló de 2 a 4 instancias al minuto 6, a 6 instancias al minuto 10
- 12-13min: Pico a 2000 VUs, p95=2500ms, tasa de error 15%
Preguntas:
1. ¿Es la política de scaling demasiado lenta? ¿Cuál debería ser el valor de target tracking?
2. ¿Por qué la latencia creció antes de que ocurriera el scaling?
3. ¿Qué explica la alta tasa de error durante el pico?
4. Recomienda cambios específicos a la configuración de auto-scaling.
Creando pruebas de carga distribuidas con Locust:
Crea una prueba de carga Locust para flujo de checkout de e-commerce:
1. Navegar productos (70% del tráfico)
2. Agregar al carrito (20% del tráfico)
3. Checkout (10% del tráfico)
Incluye:
- Tiempos de espera realistas entre acciones
- Manejo de sesión para estado del carrito
- Métricas personalizadas para cada etapa del flujo
- Configuración de setup distribuido para ejecutar en Kubernetes
Muestra cómo ejecutar esto con 10 pods worker para generar 50,000 usuarios concurrentes.
Cuándo Usar Diferentes Enfoques de Testing
Framework de Decisión de Estrategia de Testing
| Tipo de Test | Herramienta | Propósito | Cuándo Ejecutar |
|---|---|---|---|
| Smoke test | K6/Locust | Verificar que sistema funciona bajo carga mínima | Cada deployment |
| Load test | K6/Locust | Validar rendimiento bajo carga esperada | Semanalmente, antes de releases |
| Stress test | K6/Locust | Encontrar puntos de quiebre | Mensualmente, después de cambios de infra |
| Spike test | K6/Locust | Validar comportamiento de auto-scaling | Después de cambios de políticas de scaling |
| Soak test | K6/Locust | Encontrar memory leaks, agotamiento de conexiones | Trimestralmente |
Checklist de Validación de Auto-Scaling
| Validación | Qué Verificar | Criterio de Éxito |
|---|---|---|
| Disparo de scale-up | Tiempo desde breach de threshold a nueva instancia | < 3 minutos |
| Capacidad de scale-up | Nuevas instancias manejan tráfico inmediatamente | Sin fallos de requests |
| Disparo de scale-down | Instancias removidas cuando carga disminuye | Dentro de período de cooldown |
| Seguridad de scale-down | Sin terminación prematura durante tráfico | Cero requests perdidos |
| Capacidad máxima | Sistema maneja carga de máximo de instancias | Cumple SLA a máxima escala |
K6 para Testing de Escalabilidad
Test Básico de Validación de Auto-Scaling
// tests/autoscaling-validation.js
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
// Métricas personalizadas
const errorRate = new Rate('errors');
const scalingLatency = new Trend('scaling_latency');
export const options = {
scenarios: {
// Etapa 1: Calentamiento
warmup: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '2m', target: 100 },
],
gracefulRampDown: '0s',
exec: 'defaultScenario',
},
// Etapa 2: Carga sostenida (debe disparar scale-up)
sustained: {
executor: 'constant-vus',
vus: 500,
duration: '10m',
startTime: '2m',
exec: 'defaultScenario',
},
// Etapa 3: Pico (stress test de auto-scaling)
spike: {
executor: 'ramping-vus',
startVUs: 500,
stages: [
{ duration: '30s', target: 2000 },
{ duration: '1m', target: 2000 },
{ duration: '30s', target: 500 },
],
startTime: '12m',
exec: 'defaultScenario',
},
// Etapa 4: Enfriamiento (debe disparar scale-down)
cooldown: {
executor: 'ramping-vus',
startVUs: 500,
stages: [
{ duration: '5m', target: 0 },
],
startTime: '14m',
gracefulRampDown: '30s',
exec: 'defaultScenario',
},
},
thresholds: {
http_req_duration: ['p(95)<500'], // 95% de requests bajo 500ms
errors: ['rate<0.01'], // Tasa de error bajo 1%
http_req_failed: ['rate<0.01'], // Requests fallidos bajo 1%
},
};
const BASE_URL = __ENV.TARGET_URL || 'https://api.example.com';
export function defaultScenario() {
// Simular uso realista de API
const endpoints = [
{ path: '/api/users', weight: 0.5 },
{ path: '/api/orders', weight: 0.3 },
{ path: '/api/products', weight: 0.2 },
];
const random = Math.random();
let cumulative = 0;
let selectedEndpoint = endpoints[0].path;
for (const endpoint of endpoints) {
cumulative += endpoint.weight;
if (random <= cumulative) {
selectedEndpoint = endpoint.path;
break;
}
}
const response = http.get(`${BASE_URL}${selectedEndpoint}`);
const success = check(response, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
errorRate.add(!success);
// Tiempo de espera realista
sleep(Math.random() * 2 + 1);
}
Locust para Testing de Escalabilidad
Configuración de Prueba de Carga Distribuida
# locustfile.py
from locust import HttpUser, task, between, events
from locust.runners import MasterRunner
import time
import logging
class WebsiteUser(HttpUser):
wait_time = between(1, 3)
def on_start(self):
"""Inicializar sesión de usuario."""
self.client.headers = {'Content-Type': 'application/json'}
@task(5)
def browse_products(self):
"""70% del tráfico - Navegar productos."""
with self.client.get("/api/products", catch_response=True) as response:
if response.status_code == 200:
response.success()
else:
response.failure(f"Got status {response.status_code}")
@task(2)
def view_product_detail(self):
"""20% del tráfico - Ver detalles de producto."""
product_id = self.get_random_product_id()
self.client.get(f"/api/products/{product_id}")
@task(1)
def checkout_flow(self):
"""10% del tráfico - Flujo completo de checkout."""
# Agregar al carrito
self.client.post("/api/cart", json={
"product_id": self.get_random_product_id(),
"quantity": 1
})
# Checkout
with self.client.post("/api/checkout", json={
"payment_method": "card"
}, catch_response=True) as response:
if response.status_code in [200, 201]:
response.success()
elif response.status_code == 503:
response.failure("Servicio no disponible - ¿problema de scaling?")
def get_random_product_id(self):
import random
return random.randint(1, 1000)
# Métricas personalizadas para análisis de scaling
@events.request.add_listener
def track_response_time(request_type, name, response_time, response_length, **kwargs):
if response_time > 1000: # Registrar requests lentos
logging.warning(f"Request lento: {name} tomó {response_time}ms")
Deployment en Kubernetes para Locust Distribuido
# locust-master.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: locust-master
spec:
replicas: 1
selector:
matchLabels:
app: locust
role: master
template:
metadata:
labels:
app: locust
role: master
spec:
containers:
- name: locust
image: locustio/locust:2.20.0
args:
- --master
- -f
- /mnt/locust/locustfile.py
- --host
- $(TARGET_HOST)
env:
- name: TARGET_HOST
valueFrom:
configMapKeyRef:
name: locust-config
key: target_host
ports:
- containerPort: 8089
- containerPort: 5557
volumeMounts:
- name: locust-scripts
mountPath: /mnt/locust
volumes:
- name: locust-scripts
configMap:
name: locust-scripts
---
# locust-worker.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: locust-worker
spec:
replicas: 10 # 10 workers para testing distribuido
selector:
matchLabels:
app: locust
role: worker
template:
metadata:
labels:
app: locust
role: worker
spec:
containers:
- name: locust
image: locustio/locust:2.20.0
args:
- --worker
- --master-host=locust-master
- -f
- /mnt/locust/locustfile.py
volumeMounts:
- name: locust-scripts
mountPath: /mnt/locust
volumes:
- name: locust-scripts
configMap:
name: locust-scripts
Terraform para Infraestructura de Pruebas de Carga
Entorno de Prueba de Carga Efímero
# modules/load-test-infra/main.tf
variable "run_load_test" {
description = "Establecer a true para provisionar infraestructura de pruebas"
type = bool
default = false
}
variable "worker_count" {
description = "Número de workers K6/Locust"
type = number
default = 5
}
# Cluster ECS para generadores de carga
resource "aws_ecs_cluster" "load_test" {
count = var.run_load_test ? 1 : 0
name = "load-test-cluster"
setting {
name = "containerInsights"
value = "enabled"
}
tags = {
Purpose = "LoadTesting"
AutoClean = "true"
}
}
Integración CI/CD
Workflow GitHub Actions para Pruebas de Carga
name: Testing de Escalabilidad
on:
schedule:
- cron: '0 4 * * 1' # Semanalmente Lunes 4 AM
workflow_dispatch:
inputs:
test_duration:
description: 'Duración del test (ej., 10m, 1h)'
default: '20m'
max_vus:
description: 'Máximo usuarios virtuales'
default: '1000'
jobs:
load-test:
runs-on: ubuntu-latest
environment: load-test
steps:
- uses: actions/checkout@v4
- name: Configurar credenciales AWS
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.LOAD_TEST_ROLE_ARN }}
aws-region: us-east-1
- name: Setup K6
run: |
sudo apt-get update && sudo apt-get install k6
- name: Ejecutar prueba de carga
run: |
k6 run tests/autoscaling-validation.js \
--env TARGET_URL=${{ vars.TARGET_URL }} \
--duration ${{ inputs.test_duration || '20m' }} \
--vus ${{ inputs.max_vus || '1000' }} \
--out json=results/k6-results.json
Midiendo el Éxito
| Métrica | Objetivo | Cómo Rastrear |
|---|---|---|
| Latencia de scale-up | < 3 minutos desde trigger | Métricas CloudWatch ASG |
| Latencia P95 durante scale | < 500ms | Resultados K6/Locust |
| Tasa de error durante pico | < 1% | Resultados K6/Locust |
| Precisión de scale-down | Dentro de 2x período de cooldown | Logs de actividad ASG |
| Eficiencia de costos | Sin sobre-provisionamiento | AWS Cost Explorer |
Señales de que tu testing de escalabilidad no funciona:
- Tests pasan pero producción aún tiene problemas de scaling
- Políticas de scaling nunca se disparan durante tests (carga muy baja)
- Entorno de prueba no coincide con producción (diferentes tipos de instancia, límites)
- Resultados varían mucho entre ejecuciones de test (baseline inconsistente)
Conclusión
El testing efectivo de escalabilidad de infraestructura requiere escenarios realistas y herramientas apropiadas:
- Prueba tres escenarios como mínimo: carga sostenida, pico y recuperación
- Usa infraestructura efímera con Terraform para testing rentable
- Integra con CI/CD para validación regular
- Correlaciona métricas entre resultados de pruebas de carga y scaling de infraestructura
- Documenta thresholds y alerta cuando tests fallen
La idea clave: las políticas de auto-scaling necesitan validación bajo condiciones de carga reales. Los cálculos teóricos no son suficientes—prueba tu infraestructura antes de que lo hagan tus usuarios.
Ver También
- Estrategias de Testing de Terraform - Fundamentos de testing de infraestructura
- Testing de Configuración de Red - Validar que la red puede manejar escala
- Testing de Backup y Disaster Recovery - Asegurar que DR funciona a escala
- Testing de Infraestructura AWS - Estrategias más amplias de testing AWS
- Estrategias de Testing de Kubernetes - Testing de orquestación de contenedores
