Tu sistema funciona bien con 10 usuarios. Llegaron 1000 y todo explotó.
Queries sin índices, sin caché, sin rate limiting. Estos son los errores que hacen colapsar sistemas cuando llega la escala real.
Ignacio Rimini · Fundador de Quantex Agency
Publicado el · 4 min de lectura · Ingeniería
Con 10 usuarios tu sistema responde en 10ms. Con 1000 usuarios simultáneos, la base de datos colapsa, el servidor satura la CPU y los usuarios ven timeouts. Esto no es mala suerte, es consecuencia de decisiones de arquitectura que se toman al principio y se pagan caro después.
01 · Queries sin índices: el problema que más se ignora
Sin un índice, la base de datos hace un full table scan: recorre cada fila hasta encontrar las que coinciden. Con 100 filas es instantáneo. Con 1.000.000 de filas, esa misma query tarda segundos.
Ejemplo real: una tabla de órdenes con 800k registros. Query sin índice: 4.2 segundos. Con índice en user_id: 3ms.
Regla práctica: cualquier columna que usás en WHERE, JOIN o ORDER BY necesita un índice.
Cómo detectar queries lentas:
- PostgreSQL: activa
log_min_duration_statement = 100para loggear queries de más de 100ms EXPLAIN ANALYZEantes de cualquier query que sospechas es lenta- En Supabase: pestaña Database > Query Performance muestra las queries más costosas
Indexar una tabla en producción con millones de filas puede tardar varios minutos. Hacelo con CREATE INDEX CONCURRENTLY para no bloquear las escrituras.
02 · Caché con Redis: no consultes dos veces lo mismo
Si 1000 usuarios simultáneos piden el mismo listado de productos, sin caché son 1000 queries idénticas a la DB. Con Redis, son 1 query y 999 lecturas de caché a 0.1ms.
Patrón cache-aside:
- El request llega al servidor
- Busca en Redis. Si está (cache hit): retorna el valor
- Si no está (cache miss): consulta la DB, guarda el resultado en Redis con TTL, retorna el valor
Ejemplo en Node.js:
const cached = await redis.get('products:all');
if (cached) return JSON.parse(cached);
const products = await db.query('SELECT * FROM products');
await redis.setex('products:all', 300, JSON.stringify(products)); // TTL: 5 min
return products;Qué cachear: datos que cambian poco y se leen mucho (catálogos, configuraciones, rankings). Qué no cachear: datos del usuario, operaciones de escritura, información que debe ser en tiempo real.
03 · CDN para assets: sacale carga al servidor
Cada imagen, archivo JS o CSS que tu servidor sirve directamente consume CPU, memoria y ancho de banda. Con 1000 usuarios simultáneos cargando assets, el servidor colapsa antes de llegar al código de negocio.
Un CDN (Cloudflare, AWS CloudFront, Vercel) replica tus assets en edge nodes distribuidos globalmente y los sirve directamente desde ahí, sin tocar tu servidor.
Resultado: tu servidor solo procesa la lógica de negocio. Las imágenes, JS, CSS y archivos estáticos los sirve el CDN a escala infinita.
Configuración básica: apuntás tu subdominio de assets (cdn.tuapp.com) al CDN, configurás los headers de caché (Cache-Control: public, max-age=31536000) para assets con hash en el nombre, y listo.
Cloudflare tiene un plan gratuito que maneja terabytes de tráfico de assets sin costo. Para la mayoría de los proyectos es más que suficiente.
04 · Rate limiting: un usuario no tumba el sistema
Sin rate limiting, un solo usuario (o bot) puede hacer 10.000 requests por segundo y saturar tu servidor. Con 1000 usuarios legítimos, uno malicioso puede tirar el sistema entero.
Por qué es arquitectura y no solo seguridad: el rate limiting protege tu sistema de sobrecarga independientemente de si el origen es malicioso o legítimo. Un scraper, un bug en el frontend que hace infinite retries, o simplemente un usuario con una conexión muy rápida pueden generar tráfico que destruye la experiencia del resto.
Implementación por capas:
- Cloudflare / WAF: rate limit a nivel de IP antes de que el request llegue a tu servidor
- Nginx:
limit_req_zonepara limitar por IP a nivel de proxy - Aplicación: express-rate-limit, slowapi, o similar para límites por usuario autenticado
Límites recomendados:
- API pública: 100-200 req/min por IP
- Login: 10 intentos/min (protección fuerza bruta)
- Endpoints costosos (exports, reportes): 5 req/min por usuario
05 · Clustering y procesos: Node.js no es single-threaded en producción
Node.js tiene un solo thread por defecto. Si tenés un servidor con 8 cores y corrés una sola instancia de Node, estás usando el 12.5% del hardware disponible.
Cluster module: Node tiene un módulo nativo para lanzar workers que comparten el mismo puerto:
if (cluster.isPrimary) {
for (let i = 0; i < os.cpus().length; i++) cluster.fork();
} else {
app.listen(3000);
}Con 8 cores, pasás de manejar X req/s a manejar ~8X req/s con el mismo código.
PM2: en producción, PM2 simplifica el cluster y agrega restart automático si un worker crashea: pm2 start app.js -i max — lanza tantos workers como cores disponibles.
Para Python/FastAPI: gunicorn -w 4 -k uvicorn.workers.UvicornWorker app:app hace lo mismo con workers múltiples de uvicorn.
06 · Escalado horizontal: cuando vertical no alcanza
Escalar verticalmente (más RAM, más CPU al mismo servidor) tiene un límite físico y de costo. Escalar horizontalmente (más servidores iguales) puede ir infinito.
Requisitos para escalar horizontalmente:
- Stateless: la aplicación no puede guardar estado en memoria entre requests. El estado va en la DB o en Redis compartido
- Sesiones compartidas: si usás sesiones, tienen que estar en Redis, no en memoria del servidor
- Storage compartido: si los usuarios suben archivos, van a S3 o similar, no al disco local del servidor
Load balancer: un servidor (o Cloudflare, o AWS ALB) distribuye los requests entre los servidores disponibles. Si uno cae, el load balancer deja de enviarle tráfico.
Cuándo escalar: cuando el uso de CPU sostenido supera el 70-80% o la latencia empieza a degradarse bajo carga. No antes — la complejidad operacional de múltiples servidores tiene un costo.
La mayoría de estos problemas se manifiestan recién cuando el sistema tiene carga real. Pero las decisiones que los causan se toman en las primeras semanas de desarrollo: no crear índices, no planificar el caché, no pensar en stateless desde el principio.
En Quantex diseñamos sistemas que escalan desde la arquitectura inicial. Si tu sistema actual tiene cuellos de botella, hacemos una auditoría técnica y te decimos exactamente dónde están.


