Ir al contenido

SaaS con 10.000 usuarios: los 6 problemas de escala que llegan antes

Web · 8 de noviembre de 2026 · 8 min de lectura

A technical drawing: a wide field of small grey dots on the left with about twenty of them hatched white, their thin lines gathering into one line that branches to six hatched slabs stacked on the right, each slab split in two at a different point with its halves pulled apart

Diez mil usuarios registrados son poca carga. El cálculo de abajo los deja en unas veinte peticiones en curso en la hora punta. Lo que falla a esta escala son decisiones que con 500 usuarios no costaban nada: una conexión a la base de datos abierta en cada petición, una tabla leída sin índice, un email enviado mientras el usuario espera. Son los problemas de escalabilidad de un SaaS que aparecen primero, y todos cuestan menos de arreglar antes de que llegue el tráfico.

¿Por qué 10.000 usuarios ponen en apuros a un SaaS?

Porque 10.000 usuarios no son 10.000 personas conectadas a la vez. La ley de Little, un resultado de la teoría de colas, dice que las peticiones en curso son iguales a la tasa de llegada multiplicada por lo que tarda cada petición. Hagamos la cuenta para un producto B2B. Supongamos que en la hora punta está activo el 10% de los usuarios y que cada uno genera una petición cada 10 segundos. Son 1.000 personas y 100 peticiones por segundo; a 200 milisegundos por petición, hay 20 en curso. Un servidor modesto las atiende sin esfuerzo.

La carga, por tanto, es pequeña. Los fallos vienen de lo que gasta cada petición: conexiones, filas leídas, segundos de trabajo, llamadas a otros servicios. Una arquitectura que gasta un poco de más por petición funciona con 500 usuarios y se para con 10.000. Estos son los seis puntos donde pasa.

1. La base de datos se queda sin conexiones

PostgreSQL trae max_connections en 100 por defecto, y cada conexión es un proceso del servidor con su propia memoria (documentación de PostgreSQL). Los planes gestionados ponen su propio techo. En Supabase, el compute Micro admite 60 conexiones directas y 200 a través del pooler, y el límite del pooler solo sube con un compute mayor (Supabase).

En un hosting serverless, cada instancia de función activa en el mismo momento puede abrir su propia conexión. Un pico de tráfico, un deploy que arranca en frío todas las instancias o un script que inserta filas en bucle bastan para agotarlas. El síntoma es una ráfaga de errores too many connections con la CPU parada.

La solución: el tráfico de la aplicación pasa por un pooler en modo transaction, las conexiones directas se reservan para migraciones y sesiones largas, y cada instancia tiene un tope de conexiones abiertas. La guía de Supabase sobre gestión de conexiones recomienda la misma separación. Cuándo ayuda el pooler y cuándo no lo contamos en Supabase Supavisor: cuándo el pooler te salva.

2. Consultas rápidas con 1.000 filas, lentas con un millón

Una consulta sin índice lee la tabla entera. Con 1.000 filas nadie lo nota. Con 10.000 usuarios que escriben eventos, facturas y comentarios, esas tablas tienen millones de filas, y una página que se abría al instante empieza a tardar segundos.

Hay dos casos que conviene revisar primero. El primero son las claves foráneas: PostgreSQL indexa la columna referenciada pero, por diseño, no crea un índice en las columnas que la referencian. Cada columna project_id, tenant_id y user_id necesita su índice, escrito en la migración. El segundo es la paginación con OFFSET. Según la documentación, las filas que se salta un OFFSET el servidor las calcula igualmente, así que la página 500 cuesta el trabajo de 500 páginas. La paginación por clave (WHERE created_at < $ultimo) cuesta lo mismo en todas las páginas.

La row-level security añade un tercer caso: una política que llama a una función por cada fila convierte una consulta en miles de llamadas. Los patrones que la mantienen rápida están en Supabase RLS a escala.

3. El trabajo lento se ejecuta dentro de la petición

Enviar el email de bienvenida, generar la factura en PDF, llamar a un modelo de IA, avisar a un webhook: cada tarea tarda de medio segundo a medio minuto y depende de un servicio que el producto no controla. Dentro de la petición, cada segundo de ese trabajo ocupa una instancia de función, a menudo también una conexión a la base de datos, y el usuario espera.

Cuando el servicio externo va lento, las peticiones se acumulan detrás. Otra vez la ley de Little: si se duplica lo que tarda cada petición, se duplican las peticiones en curso, sin un solo usuario más.

La solución es una cola. La petición registra la tarea y responde en milisegundos; un worker la ejecuta, la reintenta si falla y guarda el resultado. Dos reglas la hacen segura. Cada tarea es idempotente, para que un reintento no envíe dos facturas. Cada tarea tiene un timeout y un máximo de reintentos, para que una entrada errónea no se repita sin fin. Una cola sobre Redis es una opción; los patrones que usamos están en los 5 patrones de Upstash Redis.

4. Un cliente ralentiza a todos los demás

En un producto multi-tenant todos los clientes comparten la misma base de datos y los mismos workers. La guía de arquitectura de Microsoft lo llama el problema del vecino ruidoso (noisy neighbor): la actividad de un tenant empeora el servicio de los demás, que ven peticiones fallidas o lentas. Con 10.000 usuarios, la distancia entre la cuenta más pequeña y la más grande basta para que ocurra. Un cliente importa 200.000 filas el lunes por la mañana y el panel va lento para todos.

La solución es tratar al tenant como una unidad que se mide y se limita. Cada consulta, tarea y línea de log lleva el id del tenant. Las operaciones pesadas (importaciones, exportaciones, ediciones masivas) pasan por una cola por tenant con su propia concurrencia, y las cuotas dependen del plan. Cuando una cuenta se queda grande para la infraestructura compartida, se mueve a una base de datos o a workers propios. El traslado es mucho más fácil si el tenant está en el esquema desde el principio, la idea de multi-tenant desde el primer día.

5. Nada limita lo que puede pedir un cliente

OWASP pone el consumo de recursos sin límites en el cuarto puesto de su API Security Top 10 de 2023 y enumera los límites que le faltan a una API vulnerable: timeouts de ejecución, memoria, registros por página y topes de gasto en proveedores externos. Un producto con 10.000 usuarios tiene scripts, integraciones y alguna cuenta que abusa. Un endpoint que devuelve todos los registros, o que llama a un modelo de IA de pago sin tope por usuario, convierte una de ellas en una caída del servicio o en una factura.

La solución: rate limits por usuario y por clave de API, un tamaño máximo de página impuesto en el servidor, un timeout en cada llamada saliente y un tope de gasto o una alerta de facturación en cada proveedor de pago. Son unas pocas líneas de código cada uno.

6. Tareas en segundo plano que leen todo

La tarea nocturna que recalcula el uso, el informe que suma la facturación, la limpieza que borra las sesiones caducadas: escritas en el lanzamiento, cada una lee la tabla entera. Con 10.000 usuarios la pasada nocturna dura horas, se solapa con la siguiente y mantiene bloqueos durante el primer tráfico de la mañana.

La solución es procesar solo lo que ha cambiado. Se guarda una marca (el último id o timestamp procesado), se trabaja por lotes de unos miles de filas con un commit después de cada uno, y las lecturas pesadas van a una réplica de lectura si el plan la tiene. Los contadores se actualizan cuando llegan los eventos, en lugar de recontar desde cero cada noche.

¿Cómo se detectan estos problemas antes que los usuarios?

Los seis aparecen en los números antes que en los tickets de soporte. Basta con vigilar cuatro:

  • Conexiones abiertas frente al límite, con alerta al 70%.
  • Las consultas más lentas por tiempo total, de pg_stat_statements, revisadas cada semana.
  • La latencia p95 por endpoint, no la media, que esconde las peticiones lentas.
  • Longitud de la cola y antigüedad de las tareas, para que un worker atascado se vea en minutos.

Después se prueba al tamaño que el producto espera alcanzar. Se llena una base de datos de staging con diez veces los datos de hoy, se repiten los endpoints más usados con una herramienta de carga como k6 y se leen los planes de las consultas con EXPLAIN ANALYZE. Una tarde de pruebas muestra cuáles de los seis problemas tiene el producto.

Qué arreglar primero

El orden lo marca el coste del fallo, no la elegancia. Los límites de conexión y los índices que faltan tiran todo el producto y se arreglan en horas: van primero. Las colas y los límites por tenant llevan días y protegen el producto de sus clientes más grandes. Pasar a lotes las tareas nocturnas puede esperar hasta que duren más de una hora. Ninguno de los seis necesita microservicios, Kubernetes ni reescribir el producto. Una sola base de datos Postgres y una aplicación bien hecha llevan un SaaS mucho más allá de los 10.000 usuarios, si cada petición gasta solo lo que necesita.

Preguntas frecuentes

Artículos relacionados

¿Prefieres que lo hagamos nosotros?

Diseñamos y desarrollamos este tipo de trabajo para clientes. Cuéntanos qué necesitas.