Estrategia para manejar la contención de recursos entre inquilinos en un entorno multiinquilino a gran escala

Hola a todos,
Estoy ejecutando una plataforma de automatización multiinquilino sobre n8n y he comenzado a observar problemas donde algunos inquilinos de alto volumen impactan la experiencia de todos los demás.
Arquitectura actual:
Cola compartida

Grupo de trabajadores compartido

Infraestructura compartida
Problemas que estoy observando:
• Un único inquilino puede saturar la cola
• Los flujos de trabajo de larga duración retrasan trabajos más pequeños
• Los inquilinos que consumen muchas APIs utilizan una capacidad de trabajadores desproporcionada
• Aumento de latencia para inquilinos de bajo volumen
Mis objetivos son:
• Asignación justa de recursos entre inquilinos
• Prevenir problemas de inquilinos ruidosos
• Mantener un rendimiento predecible
• Escalar sin sobreaprovisionamiento de infraestructura
Estoy considerando:
• Colas por inquilino
• Colas de prioridad
• Grupos de trabajadores por nivel de inquilino
• Limitación de velocidad y cuotas
• Infraestructura dedicada para inquilinos empresariales
Para los equipos que operan plataformas de flujo de trabajo multiinquilino a escala:
¿Cómo están previniendo problemas de inquilinos ruidosos?

¿Cuál es el mensaje de error (si es que hay alguno)?

Por favor, comparte tu flujo de trabajo

(Selecciona los nodos en tu lienzo y usa los atajos de teclado CMD+C/CTRL+C y CMD+V/CTRL+V para copiar y pegar el flujo de trabajo.)

Comparte el resultado devuelto por el último nodo

Información sobre tu configuración de n8n

  • Versión de n8n:
  • Base de datos (predeterminado: SQLite):
  • Configuración de n8n EXECUTIONS_PROCESS (predeterminado: own, main):
  • Ejecutando n8n a través de (Docker, npm, n8n cloud, aplicación de escritorio):
  • Sistema operativo:

Hola @Keira_Becky El enfoque más común es combinar límites de velocidad, aislamiento de colas e aislamiento de workers.

Cola Compartida + Límites por Tenant + Workers Dedicados para Tenants de Alto Volumen

Esto evita que un único tenant consuma todos los recursos disponibles.

Estrategias comunes
Aplicar límites de velocidad y cuotas por tenant
Usar colas prioritarias para diferentes niveles de servicio
Enrutar tenants de alto volumen a colas o workers dedicados
Mantener tenants más pequeños en infraestructura compartida

Para tenants a gran escala, muchos equipos utilizan: Enterprise Tenant → Cola Dedicada → Pool de Workers Dedicado

Asegúrate de evitar
Una cola global única sin límites
Tratar a todos los tenants por igual independientemente del uso
Permitir reintentos ilimitados o trabajos de larga duración en workers compartidos

La solución más limpia para el problema del vecino ruidoso es dejar de compartir lo que los inquilinos se disputan. En lugar de una única cola compartida y un grupo de trabajadores con límites añadidos, ejecuta una instancia de n8n por inquilino: su propia cola, sus propios trabajadores, su propia base de datos y clave de cifrado, su propio contenedor. El vecino ruidoso deja de ser algo que ajustes y se vuelve estructuralmente imposible, porque no hay una cola compartida para que un inquilino la inunde ni un grupo compartido para que un inquilino con muchas llamadas API agote los recursos.

La ruta de cola-compartida-más-límites (límites de velocidad por inquilino, niveles de prioridad, trabajadores dedicados para los más pesados) funciona, y es la opción correcta si estás atrapado en una única instancia grande. Pero te estás comprometiendo a ajustar para siempre los límites de velocidad, los pesos de prioridad, los límites de reintentos y la concurrencia, y un valor mal configurado o un flujo de trabajo patológico sigue afectando a otros inquilinos. La programación justa en un grupo compartido es un objetivo móvil que nunca dejas de perseguir.

El compromiso honesto con instancia-por-inquilino es lo opuesto: radio de explosión casi nulo, pero más infraestructura base ociosa y más cosas que operar. N instancias para desplegar, respaldar, monitorear y actualizar. Este costo operacional es la verdadera objeción, y es el que se puede resolver:

  • Limita cada contenedor. Límites de CPU y memoria por instancia (compose o k8s) para que incluso un flujo de trabajo descontrolado esté limitado a su propio inquilino, no al host.
  • Aísla también la ejecución. Ejecuta nodos de código en un sidecar de ejecutor de tareas externo por instancia, para que la ejecución de JS/Python esté contenida, no solo la cola.
  • Nivélalo. No necesitas una instancia por inquilino el primer día. Los inquilinos pequeños pueden compartir una instancia; proporciona a los inquilinos pesados y empresariales la suya propia. Incluso el nivel compartido es más saludable fragmentado en pocas instancias que una única cola global.
  • Pon un plano de control sobre la flota. Pasado un puñado de instancias necesitas un único lugar para ver errores, salud y ejecuciones en todas ellas, y para desplegar y respaldar sin tener que acceder por SSH de un servidor a otro.

¡Bienvenida @Keira_Becky!

La palanca más directa en el modo de cola de n8n es EXECUTIONS_CONCURRENCY_ACTIVE - configúrala por contenedor worker, no globalmente. Para el problema del vecino ruidoso, el patrón que funciona en la práctica es: ejecutar 2-3 niveles de workers con diferentes límites de concurrencia, luego enrutar los tenants pesados a su propio grupo de workers usando una clave de prefijo de cola Redis separada (configurable mediante QUEUE_BULL_PREFIX por worker). Los tenants de alto volumen obtienen un worker dedicado con EXECUTIONS_CONCURRENCY_ACTIVE más bajo (digamos 5), el nivel compartido obtiene más workers pero cada uno limitado a 10. Los workflows de ejecución prolongada son el caso más difícil - usa EXECUTIONS_TIMEOUT a nivel de instancia y EXECUTIONS_TIMEOUT_MAX por workflow para evitar que una única ejecución bloquee un worker indefinidamente. Si dos o tres tenants consistentemente maximizan su propia cola, actualizarlos a una instancia n8n dedicada suele ser el camino más limpio que intentar aislarlos dentro de un clúster compartido.

Nos golpeó la misma forma en una plataforma multi-tenant n8n+Postgres a principios de este año — llamadas LLM que superaban los TTL de Redis, un tenant lento bloqueando a todos.

Lo que realmente detuvo la hemorragia: prefijos de cola BullMQ por nivel de tenant (QUEUE_BULL_PREFIX) + techos de EXECUTIONS_CONCURRENCY_ACTIVE separados por pool de workers. El bloqueo de Redis es el camino rápido. Luego, UNIQUE de Postgres (tenant_id, message_id) con ON CONFLICT DO NOTHING como la puerta de idempotencia durable — esa es la capa de verdad cuando las llamadas de Gemini superan el TTL de Redis.

Vale la pena verificar de tu lado: ¿tu TTL de bloqueo de Redis es más largo que tu P99 de llamada LLM? Normalmente es ahí donde comienza la hemorragia de ejecuciones duplicadas.

Además — si el P95 de LLM se mantiene por debajo de 2s y pool_wait es plano, la contención está en otro lugar. Usualmente en el churn de QUEUE_RECOVERY_INTERVAL en el scheduler.