Fecha de publicación: 2025-01-15
Comparación de Modelos de Multitenancy
En el mundo del desarrollo de software SaaS, una de las decisiones arquitectónicas más importantes es cómo manejar múltiples clientes con una sola aplicación. Multitenancy es la respuesta elegante a este desafío: permite que la misma aplicación y infraestructura sirva a múltiples clientes independientes de manera eficiente y segura.
¿Qué es multitenancy?
Multitenancy es un modelo arquitectónico en el que la misma aplicación y, por lo general, la misma infraestructura de bases de datos y servidores, atiende a varios clientes independientes a los que llamamos tenants o inquilinos.
Cada tenant:
- Tiene sus propios usuarios, datos y configuraciones.
- No puede acceder ni interferir con la información de otro tenant.
- Siente que la aplicación es "suya", aunque en realidad la comparte con el resto.
Analogía del edificio de oficinas
Imagina un edificio de oficinas:
- El edificio = tu aplicación y la infraestructura
- Cada oficina = un tenant (cliente)
- Todos usan la misma estructura física (ascensores, electricidad, internet), pero cada oficina tiene llave propia, acceso controlado y decoración personalizada
Tipos de multitenancy
Aunque el concepto es único, la implementación puede variar bastante. Hay tres modelos principales que se usan en la industria:
1. Multitenancy con aislamiento lógico en la base de datos
En este modelo:
- Hay una sola instancia de base de datos (p. ej., un PostgreSQL, MySQL, etc.)
- Todas las tablas contienen los datos de todos los tenants
- Cada fila tiene un campo
tenant_idque identifica a qué cliente pertenece
Cómo se aísla la información:
- A nivel de aplicación: todas las consultas filtran por
tenant_id - A nivel de base de datos: se pueden usar políticas de Row-Level Security (RLS) para reforzar la seguridad
sql
1-- Ejemplo de tabla con tenant_id
2CREATE TABLE users (
3 id SERIAL PRIMARY KEY,
4 tenant_id UUID NOT NULL,
5 email VARCHAR(255) NOT NULL,
6 name VARCHAR(255) NOT NULL,
7 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
8);
9
10-- Índice para optimizar consultas por tenant
11CREATE INDEX idx_users_tenant_id ON users(tenant_id);
12
13-- Row Level Security (RLS) para garantizar aislamiento
14ALTER TABLE users ENABLE ROW LEVEL SECURITY;
15
16-- Política que solo permite ver datos del tenant actual
17CREATE POLICY tenant_isolation ON users
18 USING (tenant_id = current_setting('app.current_tenant_id')::UUID);Ventajas
- Muy eficiente: un solo pool de conexiones, un solo esquema que mantener
- Menor coste operativo: menos instancias y menos backups que gestionar
- Escalabilidad: más fácil añadir nuevos tenants
Desventajas
- Riesgo mayor si hay un bug en las consultas: un fallo en el filtro
tenant_idpuede exponer datos de otro cliente - Migraciones más complejas: un cambio de esquema afecta a todos los tenants a la vez
Ejemplos en la vida real
- Slack: cada workspace es un tenant, pero los mensajes y usuarios viven en las mismas bases de datos distribuidas
- Trello: múltiples tableros y equipos comparten infraestructura
2. Multitenancy con esquema dedicado
En este modelo:
- Hay una sola instancia de base de datos física, pero cada tenant tiene su propio esquema dentro de la base
- Ejemplo: en PostgreSQL,
schema_tenant_1,schema_tenant_2, etc.
Modelo de Esquemas Dedicados
sql
1-- Creación de esquemas por tenant
2CREATE SCHEMA tenant_company_a;
3CREATE SCHEMA tenant_company_b;
4
5-- Tablas en esquema dedicado
6CREATE TABLE tenant_company_a.users (
7 id SERIAL PRIMARY KEY,
8 email VARCHAR(255) NOT NULL,
9 name VARCHAR(255) NOT NULL,
10 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
11);
12
13CREATE TABLE tenant_company_b.users (
14 id SERIAL PRIMARY KEY,
15 email VARCHAR(255) NOT NULL,
16 name VARCHAR(255) NOT NULL,
17 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
18);Ventajas
- Mejor aislamiento que el modelo de un solo esquema
- Migraciones más controladas: puedes probar un cambio de esquema en un tenant antes de aplicarlo a todos
- Posible personalización de datos y estructuras para tenants específicos
Desventajas
- Gestión más compleja: hay que crear un esquema nuevo por tenant y mantener scripts de migración separados
- Escalabilidad limitada si tienes miles de tenants (demasiados esquemas en una sola base)
Ejemplos
- Aplicaciones B2B con pocos clientes de gran tamaño que necesitan personalizaciones específicas
- Plataformas de ERP que alojan a empresas grandes con requisitos distintos
3. Multitenancy con base de datos dedicada
En este modelo:
- Cada tenant tiene su propia base de datos
- Puede ser incluso en un servidor distinto
Modelo de Bases de Datos Dedicadas
Ventajas
- Aislamiento casi total de datos
- Facilidad para cumplir requisitos de compliance (ISO, HIPAA, GDPR) que exigen separación física
- Escalabilidad independiente: puedes asignar más recursos a un cliente que lo necesite
Desventajas
- Coste mucho mayor: más instancias que mantener y monitorizar
- Mantenimiento y despliegues más complejos: las migraciones deben repetirse en todas las bases
- La automatización se vuelve obligatoria para manejar muchos tenants
Ejemplos
- Sistemas bancarios que no pueden mezclar datos por regulación
- Aplicaciones médicas que manejan historiales clínicos y requieren segregación estricta
Comparativa rápida
| Modelo | Aislamiento | Coste | Escalabilidad | Complejidad |
|---|---|---|---|---|
| Lógico (campo tenant_id) | Bajo-Medio | Bajo | Alto | Baja |
| Esquema dedicado | Medio | Medio | Medio-Alto | Media |
| Base dedicada | Alto | Alto | Medio | Alta |
Factores para elegir el modelo
- Regulación y compliance: si tus clientes están en sectores con normas estrictas, el aislamiento físico puede ser obligatorio
- Cantidad de tenants: para miles de clientes, el aislamiento lógico es más manejable
- Necesidad de personalización: si un tenant requiere cambios grandes en la estructura de datos, mejor esquema o base dedicada
- Presupuesto: bases dedicadas implican un coste operativo mucho más alto
Implementación práctica: Spring Boot con PostgreSQL
Veamos cómo implementar el modelo de aislamiento lógico con Spring Boot y PostgreSQL:
kotlin
1// Entidad con tenant_id
2@Entity
3@Table(name = "users")
4data class User(
5 @Id
6 @GeneratedValue(strategy = GenerationType.IDENTITY)
7 val id: Long = 0,
8
9 @Column(name = "tenant_id", nullable = false)
10 val tenantId: UUID,
11
12 @Column(nullable = false)
13 val email: String,
14
15 @Column(nullable = false)
16 val name: String,
17
18 @CreationTimestamp
19 val createdAt: LocalDateTime = LocalDateTime.now()
20)kotlin
1// Interceptor para establecer el contexto del tenant
2@Component
3class TenantInterceptor : HandlerInterceptor {
4
5 override fun preHandle(
6 request: HttpServletRequest,
7 response: HttpServletResponse,
8 handler: Any
9 ): Boolean {
10 val token = extractJwtToken(request)
11 val tenantId = extractTenantFromToken(token)
12
13 // Establecer tenant en el contexto de la aplicación
14 TenantContext.setCurrentTenant(tenantId)
15
16 return true
17 }
18
19 override fun afterCompletion(
20 request: HttpServletRequest,
21 response: HttpServletResponse,
22 handler: Any,
23 ex: Exception?
24 ) {
25 // Limpiar contexto después de la request
26 TenantContext.clear()
27 }
28}kotlin
1// Repository con filtro automático por tenant
2@Repository
3interface UserRepository : JpaRepository<User, Long> {
4
5 @Query("SELECT u FROM User u WHERE u.tenantId = :tenantId")
6 fun findByTenantId(@Param("tenantId") tenantId: UUID): List<User>
7
8 @Query("SELECT u FROM User u WHERE u.tenantId = :tenantId AND u.email = :email")
9 fun findByTenantIdAndEmail(
10 @Param("tenantId") tenantId: UUID,
11 @Param("email") email: String
12 ): User?
13}
14
15// Service que usa el contexto del tenant automáticamente
16@Service
17class UserService(private val userRepository: UserRepository) {
18
19 fun getCurrentTenantUsers(): List<User> {
20 val currentTenantId = TenantContext.getCurrentTenant()
21 return userRepository.findByTenantId(currentTenantId)
22 }
23
24 fun createUser(email: String, name: String): User {
25 val currentTenantId = TenantContext.getCurrentTenant()
26 val user = User(
27 tenantId = currentTenantId,
28 email = email,
29 name = name
30 )
31 return userRepository.save(user)
32 }
33}Más ejemplos de empresas multitenant
- Shopify: cada tienda es un tenant, datos aislados pero compartiendo backend y capas de infraestructura global
- Netflix (en la capa de gestión de usuarios y cuentas): cada cuenta es un tenant con sus propios perfiles y datos de consumo
- Atlassian (Jira, Confluence): instancias multitenant que alojan múltiples empresas, cada una con sus propios proyectos y configuraciones
- Zoom: cada organización o cuenta empresarial es un tenant; las reuniones, usuarios y grabaciones se segmentan por account_id
- Salesforce: pionero en SaaS multitenant, cada organización tiene su configuración personalizada pero comparte la misma infraestructura masiva
Buenas prácticas en multitenancy
Seguridad
- Autenticación con contexto de tenant: incluir tenant_id en el token JWT
- Validación doble: aplicar filtros en la aplicación y Row-Level Security en la base
- Logging con tenant_id para auditoría y depuración rápida
Performance
- Limitación de recursos por tenant: evitar que un cliente acapare CPU, memoria o ancho de banda
- Índices optimizados por tenant_id en todas las tablas principales
- Caching con claves que incluyan el tenant_id
Automatización
- Scripts automatizados para el alta de nuevos tenants
- Migraciones de base de datos automáticas y versionadas
- Monitoreo por tenant para detectar problemas específicos
Observabilidad
- Métricas segmentadas por tenant
- Alertas configurables por cliente
- Dashboards de uso y performance por tenant
Desafíos comunes y cómo resolverlos
Data Leakage (Filtración de datos)
El mayor riesgo: consultas que olvidan filtrar por tenant_id
Solución: Implementa Row-Level Security a nivel de base de datos como segunda línea de defensa, y tests automatizados que verifiquen el aislamiento.
Balanceamiento de carga por tenant
Algunos tenants pueden consumir más recursos que otros
Solución: Implementa throttling y rate limiting por tenant, y considera mover clientes pesados a infraestructura dedicada.
Migraciones complejas
Cambios de esquema que afectan a miles de tenants
Solución: Migraciones incrementales, feature flags por tenant y estrategias de rollback granulares.
Arquitectura del Modelo de Aislamiento Lógico
Conclusión
El multitenancy es un patrón clave para construir aplicaciones SaaS escalables y eficientes. Elegir el modelo correcto depende de tu tipo de clientes, requisitos de seguridad y presupuesto. Ya sea que uses un solo esquema con
tenant_id o una base de datos por cliente, el objetivo es el mismo: servir a muchos como si sirvieras a uno, garantizando seguridad, personalización y eficiencia.Próximos pasos
En próximas entregas, profundizaré en cómo implementar un modelo multitenant lógico completo con Spring Boot, PostgreSQL y autenticación JWT, paso a paso, con:
- Configuración de Row-Level Security en PostgreSQL
- Implementación de interceptors y filtros automáticos
- Estrategias de testing para aplicaciones multitenant
- Monitoreo y observabilidad por tenant
¿Tienes experiencia implementando multitenancy? ¿Qué desafíos has encontrado? Me encantaría conocer tu perspectiva.


