Escalabilidad y Capacidad
Escalado horizontal vs vertical, auto-scaling, capacity planning y load testing para preparar el sistema ante la demanda.
¿Qué es escalabilidad?
La escalabilidad es la capacidad de un sistema para manejar un aumento en la carga de trabajo sin degradar su rendimiento. Un sistema escalable puede crecer para atender más usuarios, más requests o más datos sin necesidad de rediseñarlo.
La escalabilidad no es lo mismo que el rendimiento:
- Rendimiento: qué tan rápido responde el sistema con la carga actual
- Escalabilidad: qué tan bien mantiene su rendimiento cuando la carga aumenta
Escalado vertical vs horizontal
Escalado vertical (scale up)
Consiste en agregar más recursos a una máquina existente: más CPU, más RAM, más disco.
Ventajas:
- Simple de implementar — no requiere cambios en la aplicación
- No introduce complejidad de distribución
Desventajas:
- Tiene un límite físico — no se puede escalar infinitamente
- Punto único de fallo — si la máquina cae, todo cae
- Generalmente más caro a gran escala
Escalado horizontal (scale out)
Consiste en agregar más instancias del servicio y distribuir la carga entre ellas.
Ventajas:
- Teóricamente ilimitado — se pueden agregar tantas instancias como sea necesario
- Mayor resiliencia — si una instancia falla, las demás siguen funcionando
- Más económico a gran escala (commodity hardware)
Desventajas:
- Requiere que la aplicación sea stateless o maneje estado distribuido
- Introduce complejidad: balanceo de carga, consistencia de datos, sesiones distribuidas
- Más difícil de depurar
¿Cuándo usar cada uno?
| Escenario | Recomendación |
|---|---|
| Base de datos relacional | Vertical primero, luego read replicas |
| Servicios web stateless | Horizontal |
| Colas de mensajes | Horizontal (particiones) |
| Cache | Horizontal (sharding) |
| Aplicación monolítica | Vertical primero, luego descomponer |
Auto-scaling
El auto-scaling ajusta automáticamente el número de instancias según la demanda actual.
Horizontal Pod Autoscaler (HPA) en Kubernetes
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-service
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Métricas para auto-scaling
- CPU utilization: la más común, escala cuando el CPU supera un umbral
- Memory utilization: útil para aplicaciones memory-intensive
- Request rate: escala basándose en el número de requests por segundo
- Queue depth: escala cuando la cola de mensajes crece
- Custom metrics: latencia p99, errores por segundo, etc.
Buenas prácticas de auto-scaling
- Definir mínimos y máximos razonables: evitar escalar a 0 (cold start) o a infinito (costos)
- Cooldown periods: esperar antes de escalar de vuelta para evitar oscilaciones
- Escalar por adelantado: si se conocen picos predecibles (ej: Black Friday), pre-escalar
- Monitorear el auto-scaler: verificar que escala cuando debe y no oscila
Capacity planning
El capacity planning es el proceso de determinar cuántos recursos necesita el sistema para manejar la carga esperada.
Proceso
- Definir métricas clave: requests por segundo, usuarios concurrentes, tamaño de datos
- Medir la capacidad actual: cuánta carga puede manejar el sistema hoy
- Proyectar el crecimiento: basándose en datos históricos y planes de negocio
- Calcular los recursos necesarios: CPU, memoria, almacenamiento, ancho de banda
- Agregar margen de seguridad: típicamente 30-50% sobre la proyección
Ejemplo práctico
Situación actual:
- 1000 requests/segundo con 3 pods
- Cada pod maneja ~350 req/s antes de degradarse
- CPU promedio: 60%
Proyección a 6 meses:
- 3000 requests/segundo esperados
- Necesitamos: 3000 / 350 = ~9 pods
- Con margen de seguridad (30%): 12 pods
- Auto-scaling: min=9, max=15
Load testing
El load testing verifica que el sistema puede manejar la carga esperada y ayuda a identificar cuellos de botella.
Tipos de load testing
- Load test: simula la carga esperada en condiciones normales
- Stress test: incrementa la carga más allá de lo esperado para encontrar el punto de quiebre
- Spike test: simula picos repentinos de tráfico
- Soak test: mantiene carga constante durante horas para detectar memory leaks y degradación gradual
Herramientas populares
- k6: herramienta moderna de load testing con scripts en JavaScript
- Apache JMeter: herramienta clásica con interfaz gráfica
- Locust: load testing en Python, distribuido
- Artillery: load testing para APIs y microservicios
- Gatling: load testing en Scala con reportes detallados
Ejemplo con k6
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 100 }, // ramp up a 100 usuarios
{ duration: '5m', target: 100 }, // mantener 100 usuarios
{ duration: '2m', target: 200 }, // subir a 200 usuarios
{ duration: '5m', target: 200 }, // mantener 200 usuarios
{ duration: '2m', target: 0 }, // ramp down
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95% de requests < 500ms
http_req_failed: ['rate<0.01'], // menos de 1% de errores
},
};
export default function () {
const res = http.get('https://api.example.com/products');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}
Qué medir en load tests
- Throughput: requests por segundo que el sistema puede manejar
- Latencia: tiempo de respuesta (p50, p95, p99)
- Error rate: porcentaje de requests que fallan
- Recursos: CPU, memoria, conexiones de DB durante la prueba
- Punto de quiebre: carga a la que el sistema empieza a degradarse
Patrones de escalabilidad
Caching
Reducir la carga en servicios y bases de datos almacenando respuestas frecuentes:
- CDN: para assets estáticos y respuestas cacheables
- Redis/Memcached: para datos de acceso frecuente
- Cache de aplicación: para cálculos costosos
Database read replicas
Distribuir las lecturas entre múltiples réplicas de la base de datos mientras las escrituras van al primario.
Sharding
Dividir los datos horizontalmente entre múltiples instancias de base de datos basándose en una clave de partición.
Event-driven architecture
Desacoplar servicios usando eventos asincrónicos para absorber picos de carga sin saturar los servicios downstream.
Resumen
La escalabilidad requiere planificación y medición continua. El escalado horizontal es preferible para servicios stateless, el auto-scaling automatiza la respuesta a la demanda, el capacity planning anticipa las necesidades futuras y el load testing valida que el sistema puede manejar la carga esperada.