Modelo de datos multi-tenant: base por cliente o compartida
Cómo diseñar la base de datos de un software que atiende a muchos clientes: base por cliente, esquema por cliente o tablas compartidas.
Equipo menululo · Equipo fundador de menululo, Cali
Publicado el · 6 min de lectura
En este artículo respondemos:
¿Cómo se diseña la base de datos de un software que atiende a muchos clientes a la vez?
Resumen
- Un software multi-tenant atiende a muchos clientes con la misma instancia y debe garantizar que ninguno vea los datos de otro.
- Hay tres modelos clásicos: base de datos por cliente, esquema por cliente y tablas compartidas con identificador de cliente.
- No hay uno mejor en abstracto: se elige según número de clientes, exigencias de aislamiento y costo de operación, y el aislamiento se impone en la base, no solo en la interfaz.
¿Qué es la arquitectura multi-tenant?
Es un diseño en el que una sola instalación del software sirve a muchos clientes (tenants), cada uno con sus propios datos, usuarios y configuración.
El término viene de la analogía con un edificio de apartamentos: todos comparten estructura, agua y electricidad, pero cada inquilino tiene su llave. La definición de computación en la nube del NIST (SP 800-145) lo recoge en su característica de resource pooling: los recursos del proveedor se agrupan para servir a múltiples consumidores mediante un modelo multi-tenant.
Casi todo el software que se vende por suscripción funciona así: una plataforma de facturación, un sistema de agendamiento para clínicas o una herramienta de gestión de proyectos atienden a miles de empresas desde la misma aplicación. La decisión central es cómo se separan los datos de cada una.
¿Cuáles son los modelos de datos multi-tenant?
Los tres enfoques clásicos se ordenan de más aislado a más compartido: una base por cliente, un esquema por cliente dentro de una base, o todas las filas en tablas comunes con una columna que identifica al cliente.
1. Base de datos por cliente
Cada tenant tiene su propia base. La aplicación elige a cuál conectarse según quién hace la petición.
- A favor: aislamiento fuerte, respaldos y restauraciones por cliente, posibilidad de ubicar la base de un cliente en una región específica.
- En contra: cada migración de esquema se ejecuta N veces, hay que administrar muchas conexiones y el costo base crece con cada cliente, aunque use poco.
2. Esquema por cliente
Una sola base de datos con un espacio de nombres (esquema) por tenant, cada uno con las mismas tablas.
- A favor: aislamiento razonable con menos infraestructura que una base por cliente.
- En contra: las migraciones siguen multiplicándose por cliente y, con muchos tenants, el número de objetos en el catálogo de la base crece mucho.
3. Tablas compartidas con tenant_id
Todas las filas de todos los clientes viven en las mismas tablas, y cada fila lleva una columna que indica a quién pertenece.
- A favor: una sola migración, uso eficiente de recursos, fácil de escalar a muchísimos clientes pequeños, consultas globales sencillas para analítica interna.
- En contra: una consulta sin el filtro correcto expone datos de otros clientes; un cliente muy grande puede afectar el rendimiento de los demás.
¿Cómo se comparan los tres modelos?
Resumido: más aislamiento significa más costo operativo, y más compartición exige más disciplina de seguridad.
| Criterio | Base por cliente | Esquema por cliente | Tablas compartidas |
|---|---|---|---|
| Aislamiento de datos | Muy alto | Alto | Depende de controles |
| Costo por cliente nuevo | Alto | Medio | Bajo |
| Migraciones de esquema | Una por base | Una por esquema | Una sola |
| Restaurar un solo cliente | Sencillo | Moderado | Complejo |
| Escala a miles de clientes pequeños | Difícil | Moderada | Natural |
| Riesgo de “vecino ruidoso” | Bajo | Medio | Alto |
Muchos productos terminan en un modelo híbrido: tablas compartidas para la mayoría y bases dedicadas para los clientes grandes o con exigencias regulatorias.
¿Cómo se evita que un cliente vea datos de otro?
Aplicando el filtro por cliente en la capa más baja posible, idealmente en la propia base de datos, en lugar de confiar en que cada consulta del código lo recuerde.
Las fallas de control de acceso son un riesgo muy real: la categoría Broken Access Control encabeza el OWASP Top 10 de 2021, tras subir desde el quinto lugar. En un sistema multi-tenant, el caso típico es un endpoint que recibe un identificador y devuelve el registro sin comprobar que pertenece al cliente autenticado.
En bases de datos relacionales de código abierto como PostgreSQL existe la seguridad a nivel de fila (Row-Level Security): políticas que la base aplica automáticamente a cada consulta.
-- Cada fila pertenece a un tenant
ALTER TABLE facturas ENABLE ROW LEVEL SECURITY;
-- Solo se ven y modifican filas del tenant de la sesión actual
CREATE POLICY aislamiento_tenant ON facturas
USING (tenant_id = current_setting('app.tenant_id')::uuid)
WITH CHECK (tenant_id = current_setting('app.tenant_id')::uuid);
-- La aplicación fija el tenant al inicio de cada transacción
-- SET LOCAL app.tenant_id = '6f1c...';
Con esto, aunque alguien olvide un WHERE tenant_id = ..., la base no devuelve filas ajenas. Hay que cuidar un detalle: los roles con privilegios elevados o dueños de la tabla pueden saltarse estas políticas según su configuración, así que la aplicación no debería conectarse con ellos.
Si la base no ofrece algo equivalente, el filtro debe centralizarse en una capa de acceso a datos que no permita consultar sin tenant, y cubrirse con pruebas automáticas que intenten leer datos de otro cliente.
¿Qué es el problema del vecino ruidoso?
Es cuando un cliente que consume muchos recursos degrada el servicio de los demás que comparten la misma infraestructura.
Un reporte pesado, una importación masiva o un error que dispara reintentos en bucle pueden saturar la base compartida. Las mitigaciones habituales son límites de uso por tenant, colas de trabajo con cupos por cliente (lo tratamos en colas de reintentos), réplicas de solo lectura para reportes y, en último caso, mover al cliente grande a recursos dedicados.
¿Qué errores se repiten en sistemas multi-tenant?
Casi todos son lugares donde el identificador del cliente se pierde por el camino.
- Cachés sin el tenant en la clave, que sirven a un cliente la respuesta de otro.
- Tareas en segundo plano globales que procesan datos sin fijar el contexto del cliente.
- Identificadores secuenciales expuestos, que invitan a probar el número siguiente.
- Archivos subidos en rutas compartidas sin prefijo por cliente ni control de acceso.
- Registros de errores o analítica que mezclan datos personales de distintos clientes.
- Sincronización entre dispositivos que no valida el tenant en el servidor. Si tu app funciona sin conexión, revisa offline-first explicado y algoritmos de sincronización: cada cambio que llega desde un dispositivo debe verificarse contra el cliente al que dice pertenecer.
¿Qué modelo conviene elegir?
Para la mayoría de los productos que esperan muchos clientes pequeños, tablas compartidas con aislamiento impuesto en la base; para pocos clientes grandes o regulados, bases dedicadas.
Preguntas que ayudan a decidir:
- ¿Cuántos clientes esperas en tres años: decenas o miles?
- ¿Algún cliente exige por contrato que sus datos estén separados físicamente o en un país específico?
- ¿Necesitas restaurar a un solo cliente sin tocar a los demás?
- ¿Tu equipo puede ejecutar y vigilar una migración sobre cientos de bases?
Y una recomendación de diseño independiente del modelo: incluye el identificador de cliente en todos los datos desde el primer día. Pasar después de tablas compartidas a bases dedicadas es mucho más fácil si cada fila ya sabe a quién pertenece.
Preguntas frecuentes
¿Qué es un sistema multi-tenant?
Un sistema multi-tenant es un software en el que una misma instancia atiende a muchos clientes, llamados tenants, mientras mantiene sus datos separados. El NIST lo describe como parte de la computación en la nube: recursos compartidos que sirven a múltiples consumidores y se asignan según la demanda.
¿Qué modelo multi-tenant es más seguro?
La base de datos por cliente ofrece el aislamiento más fuerte, porque una consulta mal escrita no puede cruzar datos de otro cliente. Las tablas compartidas pueden ser seguras si el filtro por cliente se aplica en la propia base, por ejemplo con políticas de seguridad a nivel de fila, y no solo en el código.
¿Cuándo conviene una base de datos por cliente?
Conviene cuando hay pocos clientes grandes, exigencias regulatorias de aislamiento o residencia de datos, o necesidad de restaurar y migrar a cada cliente por separado. Con miles de clientes pequeños suele ser más caro de operar, porque cada migración y cada respaldo se multiplican por el número de bases.
Sigue leyendo
- Arquitectura de software 7 min de lectura
Colas de reintentos: idempotencia, backoff y dead-letter queues
Cómo funciona una cola de reintentos: idempotencia, backoff exponencial con jitter, dead-letter queues y el patrón outbox para no perder datos.
- Algoritmos 7 min de lectura
Algoritmos de sincronización: LWW, relojes vectoriales y CRDT
Cómo dos copias de un mismo dato vuelven a estar de acuerdo: last-write-wins, relojes de Lamport, relojes vectoriales y CRDT con ejemplos.
- Arquitectura de software 7 min de lectura
Offline-first: cómo diseñar apps que funcionan sin internet
Qué es la arquitectura offline-first, cómo funcionan la base local, la cola de escritura y la sincronización, y cuándo conviene usarla.