Patrones Multi-inquilino Explicados
La multi-inquilinidad es la práctica de servir a muchos clientes, o inquilinos, desde una infraestructura compartida, manteniendo los datos de cada inquilino aislados de los de cualquier otro inquilino.
Busca en todas las páginas de la documentación
La multi-inquilinidad es la práctica de servir a muchos clientes, o inquilinos, desde una infraestructura compartida, manteniendo los datos de cada inquilino aislados de los de cualquier otro inquilino.
Cada patrón para hacer esto en PostgreSQL, desde una columna tenant_id hasta una base de datos completamente separada por cliente, se ubica en algún lugar de un espectro subyacente entre la simplicidad operativa y la fortaleza del aislamiento.
Esta página explica ese espectro directamente, para que las páginas más concretas de esta sección (consultas de esquema compartido, políticas de RLS, esquema por inquilino, base de datos por inquilino) se lean como puntos a lo largo de él en lugar de técnicas no relacionadas.
El patrón más simple, esquema compartido con una columna tenant_id, coloca las filas de cada inquilino en las mismas tablas, distinguidas solo por un valor tenant_id.
CREATE TABLE projects (
tenant_id uuid NOT NULL REFERENCES tenants (tenant_id),
project_id bigint GENERATED ALWAYS AS IDENTITY,
name text NOT NULL,
PRIMARY KEY (tenant_id, project_id)
);Este es el patrón más económico de operar, porque una migración, una copia de seguridad y un grupo de conexiones sirven a todos los inquilinos a la vez.
Esquema por inquilino sube un nivel en el espectro al dar a cada inquilino un esquema PostgreSQL dedicado con DDL de tabla duplicado, obteniendo aislamiento de espacio de nombres a costa de ejecutar cada migración una vez por esquema de inquilino.
Base de datos por inquilino avanza aún más, dando a cada inquilino una base de datos completamente separada con ciclos de copia de seguridad, restauración y actualización independientes, que es el aislamiento más fuerte que ofrece PostgreSQL dentro de un solo clúster.
Cada paso a lo largo de este espectro, desde el esquema compartido hasta la base de datos por inquilino, compra una contención de radio de explosión más fuerte a cambio de más infraestructura para operar y más lugares donde una migración puede fallar.
La multi-inquilinidad de esquema compartido pone toda la carga de corrección en que cada consulta recuerde filtrar por tenant_id, lo cual es una garantía frágil en la que confiar para algo tan serio como fugas de datos entre inquilinos.
La seguridad a nivel de fila (RLS) existe para hacer que esa garantía sea estructural en lugar de convencional, al adjuntar una política directamente a la tabla que PostgreSQL aplica independientemente de si la consulta de la aplicación recordó una cláusula WHERE tenant_id = ....
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
ALTER TABLE projects FORCE ROW LEVEL SECURITY;
CREATE POLICY projects_tenant_isolation ON projects
USING (tenant_id = current_setting('app.tenant_id', true)::uuid);RLS es una red de seguridad superpuesta al filtrado a nivel de aplicación, no un sustituto del mismo, porque una política todavía depende de que la sesión establezca correctamente app.tenant_id para cada conexión.
El problema del vecino ruidoso es el modo de falla característico del patrón de esquema compartido: la carga de trabajo inusualmente grande de un inquilino consume una proporción desproporcionada de CPU, E/S o contención de bloqueos, degradando el rendimiento para todos los demás inquilinos que comparten las mismas tablas y grupo de conexiones.
Detectarlo requiere observabilidad por inquilino, como agrupar pg_stat_statements o registros de auditoría por tenant_id, ya que PostgreSQL en sí mismo no tiene un concepto nativo de un inquilino para aislar recursos.
El esquema por inquilino y la base de datos por inquilino reducen el riesgo de vecinos ruidosos estructuralmente, ya que los datos de cada inquilino y, en el caso de la base de datos por inquilino, el grupo de conexiones, están físicamente separados de los de cualquier otro inquilino.
Los requisitos de cumplimiento a menudo obligan a la decisión de aislamiento en lugar de dejarla puramente como una compensación de rendimiento.
Un cliente empresarial regulado puede requerir contractualmente que sus datos nunca compartan almacenamiento físico o un grupo de conexiones con ningún otro inquilino, lo que efectivamente exige la base de datos por inquilino independientemente de lo que sugieran las economías del esquema compartido.
Muchos productos SaaS reales no eligen un patrón para todo el sistema; ejecutan esquema compartido + RLS para la mayoría de los inquilinos y reservan esquema por inquilino o base de datos por inquilino para un nivel empresarial dispuesto a pagar por ese aislamiento.
Ese enfoque por niveles significa que la capa de enrutamiento de conexiones, no solo la capa de esquema, tiene que saber qué patrón utiliza un inquilino determinado, lo que agrega complejidad real a la aplicación a cambio de servir a ambos extremos del mercado desde un solo producto.
| Enfoque | Fortaleza | Debilidad | Mejor Ajuste |
|---|---|---|---|
| Esquema compartido + tenant_id | Más económico de operar; una migración sirve a todos los inquilinos | La corrección depende de que cada consulta filtre correctamente; riesgo de vecino ruidoso | Productos SaaS en etapas iniciales, la mayoría de los niveles de inquilinos de autoservicio |
| Esquema compartido + RLS | Aislamiento aplicado por la base de datos como red de seguridad | Todavía comparte recursos físicos; la corrección de la política depende de la configuración de la sesión | Cualquier producto de esquema compartido que busque defensa en profundidad |
| Esquema por inquilino | Aislamiento de espacio de nombres más fuerte; exportación de datos por inquilino más fácil | Las migraciones se ejecutan una vez por esquema de inquilino; más difícil de escalar a miles de inquilinos | Inquilinos del mercado medio que necesitan más aislamiento sin separación completa de la base de datos |
| Base de datos por inquilino | Aislamiento más fuerte; copia de seguridad, restauración y escalado independientes por inquilino | Mayor costo operativo; los informes entre inquilinos requieren federación | Inquilinos regulados o empresariales con requisitos de aislamiento contractuales |
La agrupación de conexiones también debe reconsiderarse en cada punto de este espectro, ya que PgBouncer agrupa por base de datos, no por esquema, por lo que los inquilinos de esquema por inquilino todavía comparten un grupo, mientras que los inquilinos de base de datos por inquilino necesitan un grupo por base de datos o enrutamiento dinámico.
WHERE tenant_id = ... faltante en cualquier ruta de consulta es una fuga de datos entre inquilinos, por lo que la multi-inquilinidad de esquema compartido se considera el eslabón más débil en este espectro sin salvaguardias adicionales.Los patrones multi-inquilino van desde el esquema compartido (más económico, aislamiento más débil) a través del esquema por inquilino hasta la base de datos por inquilino (más caro, aislamiento más fuerte).
Cada patrón concreto de esta sección es un punto en ese mismo espectro.
Un esquema compartido donde las filas de cada inquilino viven en las mismas tablas, distinguidas por una columna tenant_id en la que cada consulta debe filtrar.
Es el más económico de operar, pero pone el mayor peso en la corrección de las consultas.
No, RLS es una red de seguridad aplicada por la base de datos que atrapa las consultas que carecen de un filtro de inquilino, pero aún depende de que la sesión establezca correctamente el contexto del inquilino.
Complementa el filtrado de la aplicación en lugar de reemplazarlo.
Es cuando la carga de trabajo desproporcionadamente pesada de un inquilino degrada el rendimiento de otros inquilinos que comparten las mismas tablas y grupo de conexiones.
Es más visible en la multi-inquilinidad de esquema compartido y se reduce a medida que el aislamiento se fortalece.
Cuando un conjunto limitado de inquilinos necesita un aislamiento de espacio de nombres más fuerte o una exportación de datos por inquilino más fácil de la que puede ofrecer una tabla compartida, sin el costo operativo completo de bases de datos separadas.
Se vuelve más difícil de justificar una vez que el número de inquilinos crece a miles.
Lo más común es cuando el contrato o requisito regulatorio de un inquilino exige que sus datos nunca compartan almacenamiento físico o un grupo de conexiones con ningún otro inquilino.
También es útil cuando la escala de un inquilino realmente necesita ciclos de copia de seguridad y restauración independientes.
Sí, y muchos sistemas SaaS reales lo hacen: esquema compartido + RLS para la mayoría de los inquilinos, con esquema por inquilino o base de datos por inquilino reservados para un nivel empresarial.
Esto requiere que la capa de enrutamiento de conexiones sepa qué patrón utiliza cada inquilino.
PgBouncer agrupa por base de datos, no por esquema, por lo que los inquilinos de esquema por inquilino todavía comparten un grupo, mientras que los inquilinos de base de datos por inquilino típicamente necesitan un grupo por base de datos o enrutamiento dinámico.
Este es un costo operativo que crece junto con la fortaleza del aislamiento.
Solo si está limitada al inquilino, como UNIQUE (tenant_id, slug).
Una restricción UNIQUE (slug) global evita incorrectamente que dos inquilinos diferentes utilicen el mismo valor.
A través de la observabilidad por inquilino, como agrupar la actividad de consulta o pg_stat_statements por tenant_id, ya que PostgreSQL no tiene un concepto nativo de inquilino para aislar recursos automáticamente.
Este trabajo de detección es lo que generalmente desencadena un movimiento a un nivel de aislamiento más fuerte para ese inquilino.
No necesariamente para análisis entre inquilinos: la base de datos por inquilino aísla bien las cargas de trabajo, pero hace que cualquier informe que abarque inquilinos requiera federación en lugar de una simple unión.
La fortaleza del aislamiento y la conveniencia de las consultas entre inquilinos se mueven en direcciones opuestas.
El número esperado de inquilinos, los requisitos de cumplimiento y si algún inquilino está dispuesto a pagar por un aislamiento más fuerte.
Los productos en etapas iniciales recurren por defecto al esquema compartido y solo mueven inquilinos específicos en el espectro cuando un requisito concreto lo exige.
Versiones de Stack: Esta página fue escrita para PostgreSQL 18.4 (estable 18, mantenimiento 17) y PgBouncer 1.x.
Revisado por Chris St. John·Última actualización: 15 jul 2026