Multi-Tenant vs Single-Tenant | Scegliere l'Architettura SaaS Giusta
Un confronto tecnico tra architetture SaaS multi-tenant e single-tenant. Scopri i compromessi e come scegliere l'approccio giusto per il tuo prodotto.
Ogni prodotto SaaS deve rispondere a una domanda fondamentale: come servi piu’ clienti dallo stesso software? La risposta e’ il tuo modello di tenancy. Influenza costi, sicurezza, prestazioni e quanto velocemente puoi rilasciare. Azzeccarlo presto ti risparmia migrazioni dolorose in seguito.
Definizioni
Multi-tenant
Un’istanza dell’applicazione serve tutti i clienti. Tutti condividono gli stessi server, lo stesso codebase e spesso lo stesso database. I dati di ogni cliente sono isolati logicamente, ma l’infrastruttura e’ condivisa.
Pensalo come un condominio. Ogni inquilino vive nello stesso edificio, condivide l’ascensore e i corridoi, ma ha il proprio appartamento chiuso a chiave con i propri mobili.
Single-tenant
Ogni cliente ha la propria istanza dedicata dell’applicazione. Server separati, database separati, a volte codebase separati. Nulla e’ condiviso tra i clienti.
Pensalo come case indipendenti. Ogni inquilino ha il proprio edificio, il proprio impianto idraulico, il proprio giardino. Isolamento completo, ma piu’ costoso da mantenere.
Come Funziona il Multi-Tenancy
Ci sono tre approcci comuni all’architettura multi-tenant, ognuno con compromessi diversi.
Modello 1: Applicazione condivisa, database condiviso
Tutti i tenant condividono un’unica istanza dell’applicazione e un unico database. I dati dei tenant sono separati usando un identificatore del tenant (solitamente una colonna tenant_id) su ogni tabella.
Architettura:
- Un server applicativo (o cluster) gestisce tutte le richieste.
- Un database archivia tutti i dati dei tenant.
- Ogni query include una clausola
WHERE tenant_id = ?per limitare i dati al tenant corretto.
Pro:
- Costo infrastrutturale piu’ basso. Un database, un deployment dell’app.
- Piu’ semplice da deployare e aggiornare. Rilasci una volta, tutti ricevono la modifica.
- Facile aggregare dati tra tenant per analytics e reportistica.
Contro:
- Rischio piu’ alto di fuga dati se una query dimentica il filtro tenant.
- Un tenant rumoroso puo’ degradare le prestazioni per tutti.
- Le migrazioni database colpiscono tutti i tenant simultaneamente.
- Piu’ difficile conformarsi ai regolamenti sulla residenza dei dati.
Questo e’ l’approccio piu’ comune per prodotti SaaS B2B con un gran numero di clienti di piccole e medie dimensioni.
Modello 2: Applicazione condivisa, database separati
Tutti i tenant condividono la stessa istanza dell’applicazione, ma ogni tenant ha il proprio database. L’applicazione instrada le query al database corretto in base al tenant autenticato.
Architettura:
- Un server applicativo (o cluster) gestisce tutte le richieste.
- Un database separato per ogni tenant.
- Un livello di routing mappa l’identita’ del tenant alla connessione database corretta.
Pro:
- Isolamento dati piu’ forte. Nessun rischio di query cross-tenant.
- Piu’ facile soddisfare i requisiti di residenza dei dati. Puoi posizionare ogni database nella regione richiesta dal tenant.
- Backup e ripristino per tenant sono semplici.
- L’uso intenso di un tenant non blocchera’ le tabelle per gli altri.
Contro:
- Piu’ infrastruttura da gestire. Centinaia di tenant significano centinaia di database.
- Le migrazioni dello schema devono essere applicate a ogni database individualmente.
- La reportistica cross-tenant richiede query su database multipli.
- Costo piu’ alto rispetto a un modello completamente condiviso.
Questo e’ un forte punto intermedio per prodotti che necessitano di migliore isolamento senza il costo del single-tenancy completo.
Modello 3: Applicazione separata, database separato
Ogni tenant ha la propria istanza dell’applicazione e il proprio database. Completamente isolato. Questo e’ essenzialmente single-tenancy, ma gestito dal provider SaaS invece che dal cliente.
Architettura:
- Un deployment applicativo dedicato per tenant.
- Un database dedicato per tenant.
- Un livello di routing (spesso un load balancer o API gateway) dirige il traffico all’istanza corretta.
Pro:
- Isolamento completo. Nessuna risorsa condivisa tra tenant.
- Massima flessibilita’ per personalizzazione per tenant.
- Le prestazioni di un tenant non influenzano mai un altro.
- La storia di conformita’ piu’ semplice.
Contro:
- Costo infrastrutturale piu’ alto in assoluto.
- La complessita’ del deployment cresce linearmente con il numero di tenant.
- Gli aggiornamenti devono essere distribuiti a ogni istanza individualmente (o automatizzati con molta attenzione).
- Non scala economicamente per grandi numeri di piccoli tenant.
Questo modello ha senso per SaaS enterprise dove i clienti richiedono infrastruttura dedicata e sono disposti a pagare un premium per questo.
Pro e Contro a Colpo d’Occhio
| Fattore | Multi-Tenant (DB Condiviso) | Multi-Tenant (DB Separato) | Single-Tenant |
|---|---|---|---|
| Costo infrastruttura | Piu’ basso | Medio | Piu’ alto |
| Isolamento dati | Logico (a livello di riga) | Fisico (a livello di database) | Completo |
| Complessita’ deployment | Bassa | Media | Alta |
| Velocita’ aggiornamenti | Istantanea per tutti | App istantanea, migrazioni per-DB | Rollout per-istanza |
| Personalizzazione | Limitata | Limitata | Completa |
| Conformita’ | Piu’ difficile | Moderata | Piu’ facile |
| Scalabilita’ (numero tenant) | Eccellente | Buona | Scarsa |
| Rischio noisy neighbor | Alto | Medio | Nessuno |
Isolamento Dati e Sicurezza
L’isolamento dei dati e’ la considerazione piu’ importante in qualsiasi modello di tenancy. Una violazione di sicurezza dove un tenant puo’ accedere ai dati di un altro tenant e’ catastrofica per un’azienda SaaS. Puo’ distruggere la fiducia, violare le normative e chiudere l’azienda.
Row-level security
In un modello a database condiviso, la Row-Level Security (RLS) di PostgreSQL e’ una delle difese piu’ forti contro la fuga di dati. RLS impone l’isolamento dei tenant a livello di database, non a livello applicativo. Anche se il codice applicativo ha un bug che dimentica di filtrare per tenant, il database stesso previene l’accesso cross-tenant.
Ecco come configurarlo:
-- Enable RLS on a table
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
-- Create a policy that restricts access to the current tenant
CREATE POLICY tenant_isolation ON projects
USING (tenant_id = current_setting('app.current_tenant_id')::uuid);
-- Force RLS even for table owners
ALTER TABLE projects FORCE ROW LEVEL SECURITY;
Prima di eseguire qualsiasi query, imposta il contesto del tenant:
-- Set at the beginning of each request/transaction
SET LOCAL app.current_tenant_id = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';
-- Now this query automatically returns only the current tenant's data
SELECT * FROM projects;
-- No WHERE clause needed. RLS handles it.
Isolamento a livello applicativo
Oltre alla sicurezza a livello di database, la tua applicazione dovrebbe imporre i confini del tenant:
// Middleware that sets tenant context on every request
async function tenantMiddleware(req: Request, res: Response, next: NextFunction) {
const tenantId = extractTenantId(req); // From JWT, subdomain, or header
if (!tenantId) {
return res.status(401).json({ error: "Tenant not identified" });
}
// Set tenant context for the database connection
await db.raw(`SET LOCAL app.current_tenant_id = '${tenantId}'`);
req.tenantId = tenantId;
next();
}
La difesa in profondita’ e’ il principio qui. Non affidarti mai a un singolo livello di isolamento. Combina filtraggio a livello applicativo, sicurezza a livello di database e audit di sicurezza regolari.
Considerazioni sulle Prestazioni
Sfide del database condiviso
In un database condiviso, tutti i tenant competono per le stesse risorse. Un tenant che esegue un report pesante puo’ rallentare le query per tutti gli altri. Le mitigazioni includono:
- Connection pooling. Usa PgBouncer o uno strumento simile per impedire a un tenant di esaurire le connessioni al database.
- Timeout sulle query. Imposta tempi di esecuzione massimi cosi’ che una query fuori controllo non possa bloccare le risorse indefinitamente.
- Rate limiting. Imponi limiti per-tenant su richieste API e operazioni database.
- Read replica. Instrada le operazioni di lettura pesanti (report, esportazioni) verso una replica cosi’ che non influenzino il database primario.
Vantaggi dei database separati
Con database per-tenant, l’isolamento delle prestazioni e’ integrato. Il carico di lavoro pesante di un tenant influisce solo sul proprio database. Puoi anche provisionare database piu’ grandi o piu’ piccoli in base al piano e all’utilizzo di ogni tenant.
Il compromesso e’ l’overhead di gestione. Monitorare 500 database e’ piu’ difficile che monitorarne uno. Gli strumenti automatizzati diventano essenziali.
Implicazioni di Costo su Scala
Guardiamo alcuni numeri approssimativi. Supponiamo tu abbia 100 tenant.
Database condiviso (multi-tenant):
- 1 cluster applicativo: ~200 euro/mese
- 1 istanza PostgreSQL gestita: ~100 euro/mese
- Totale: ~300 euro/mese (3 euro per tenant)
Database separati (multi-tenant):
- 1 cluster applicativo: ~200 euro/mese
- 100 piccole istanze database: ~2.000 euro/mese
- Totale: ~2.200 euro/mese (22 euro per tenant)
Single-tenant:
- 100 istanze applicative: ~5.000 euro/mese
- 100 istanze database: ~2.000 euro/mese
- Totale: ~7.000 euro/mese (70 euro per tenant)
Questi numeri sono semplificati, ma il pattern regge. L’infrastruttura condivisa e’ drammaticamente piu’ economica. A 1.000 tenant, il divario diventa ancora piu’ ampio.
Ecco perche’ il pricing deve allinearsi con l’architettura. Se addebiti 20 euro al mese e fai girare infrastruttura single-tenant a 70 euro per tenant, perdi soldi su ogni cliente.
Quando Scegliere Multi-Tenant
L’architettura multi-tenant e’ la scelta giusta quando:
- Stai costruendo SaaS B2B per PMI. Alto volume, punti di prezzo piu’ bassi e set di funzionalita’ standard.
- L’efficienza dei costi conta. Hai bisogno di mantenere i costi infrastrutturali bassi rispetto ai ricavi.
- Vuoi aggiornamenti veloci e uniformi. Deploya una volta, tutti i tenant ricevono il miglioramento.
- I tuoi clienti non richiedono infrastruttura dedicata. La maggior parte delle piccole e medie imprese non si preoccupa di dove vivono i loro dati, purche’ siano al sicuro.
- Sei nelle fasi iniziali. Inizia multi-tenant. E’ piu’ economico e piu’ semplice. Puoi sempre offrire single-tenant successivamente per clienti enterprise.
Quando Scegliere Single-Tenant
L’architettura single-tenant ha senso quando:
- Stai vendendo a enterprise. Le grandi organizzazioni spesso richiedono infrastruttura dedicata come parte del loro processo di acquisto.
- La conformita’ lo richiede. Settori come sanita’ (HIPAA), finanza (SOX, PCI-DSS) e pubblica amministrazione hanno requisiti stringenti di isolamento dati.
- I clienti hanno bisogno di personalizzazione. Se ogni cliente richiede configurazioni, integrazioni o persino funzionalita’ diverse, il single-tenant ti da’ la flessibilita’.
- Il tuo punto di prezzo lo supporta. Se addebiti 5.000 euro o piu’ al mese per cliente, il costo infrastrutturale e’ facilmente giustificato.
- La residenza dei dati e’ un requisito rigido. Quando i dati devono risiedere in un paese specifico, l’infrastruttura separata per tenant e’ l’approccio piu’ diretto.
Approcci Ibridi
Non devi sceglierne solo uno. Molte aziende SaaS di successo usano un modello ibrido:
- Multi-tenant per i livelli standard. Clienti free, starter e pro condividono l’infrastruttura. Questo tiene bassi i costi e ti permette di scalare.
- Single-tenant per enterprise. I clienti premium ottengono istanze dedicate con SLA personalizzati, certificazioni di conformita’ e supporto dedicato.
Il codice applicativo e’ lo stesso. Il modello di deployment differisce. Questo richiede una buona automazione dell’infrastruttura, ma e’ un pattern collaudato.
Come implementare un modello ibrido
- Costruisci l’app come multi-tenant prima. Tutta la logica di isolamento dei tenant resta la stessa indipendentemente dal modello di deployment.
- Usa infrastructure-as-code (Terraform, Pulumi o CDK) per automatizzare la creazione degli ambienti.
- Crea una pipeline di provisioning che possa lanciare un nuovo ambiente dedicato in minuti, non giorni.
- Mantieni un singolo codebase. La stessa immagine Docker gira in ambienti condivisi e dedicati. La configurazione (non il codice) determina il comportamento.
Strategie Database in Dettaglio
Il database e’ dove le decisioni di tenancy hanno il maggior impatto. Ecco tre strategie collaudate.
Strategia 1: Tabelle condivise con tenant_id
Ogni tabella ha una colonna tenant_id. Tutte le query filtrano per essa.
CREATE TABLE projects (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
name TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_projects_tenant ON projects(tenant_id);
-- Always query with tenant context
SELECT * FROM projects WHERE tenant_id = $1;
Ideale per: La maggior parte dei prodotti SaaS. Semplice, economico, ben compreso.
Strategia 2: Schema per tenant
Ogni tenant ha il proprio schema PostgreSQL all’interno di un database condiviso. Le tabelle hanno la stessa struttura, ma i dati sono fisicamente separati.
-- Create a schema for a new tenant
CREATE SCHEMA tenant_abc123;
-- Create tables in the tenant's schema
CREATE TABLE tenant_abc123.projects (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
-- Set the search path per request
SET search_path TO tenant_abc123, public;
-- Now queries are automatically scoped
SELECT * FROM projects;
Ideale per: Prodotti che necessitano di isolamento piu’ forte del livello riga ma non vogliono il costo di database separati. Funziona bene fino a qualche centinaio di tenant.
Strategia 3: Database separati
Ogni tenant ha un’istanza PostgreSQL dedicata (o un database dedicato su un server condiviso).
// Database connection routing
class TenantDatabaseRouter {
private connections: Map<string, DatabasePool> = new Map();
async getConnection(tenantId: string): Promise<DatabasePool> {
if (this.connections.has(tenantId)) {
return this.connections.get(tenantId)!;
}
const config = await this.loadTenantDbConfig(tenantId);
const pool = new DatabasePool({
host: config.host,
port: config.port,
database: config.database,
user: config.user,
password: config.password,
});
this.connections.set(tenantId, pool);
return pool;
}
private async loadTenantDbConfig(tenantId: string): Promise<DbConfig> {
// Look up tenant's database connection details
// from a central configuration store
return await configStore.get(`tenants/${tenantId}/database`);
}
}
Ideale per: SaaS enterprise con clienti di alto valore, requisiti di conformita’ stringenti o obblighi di residenza dei dati.
Prendere la Decisione
Ecco un semplice framework decisionale:
- Qual e’ la dimensione del tuo cliente target? PMI punta al multi-tenant. Enterprise punta al single-tenant o ibrido.
- Qual e’ il tuo punto di prezzo? Sotto i 100 euro/mese, hai bisogno del multi-tenant per essere profittevole. Sopra i 1.000 euro/mese, il single-tenant diventa praticabile.
- Quali sono i requisiti di conformita’? I settori regolamentati spesso richiedono isolamento piu’ forte.
- Quanti tenant ti aspetti? Centinaia o migliaia di tenant necessitano infrastruttura condivisa. Da dieci a cinquanta grandi tenant possono funzionare con istanze dedicate.
- Qual e’ la capacita’ operativa del tuo team? Il single-tenant richiede piu’ investimento DevOps. Il multi-tenant e’ operativamente piu’ semplice.
Se sei incerto, inizia con multi-tenant usando un database condiviso e row-level security. E’ l’opzione a costo piu’ basso, e’ sicura se implementata correttamente e mantiene la tua architettura semplice. Puoi sempre aggiungere un tier dedicato per clienti enterprise successivamente.
La Conclusione
Non esiste un modello di tenancy universalmente corretto. La scelta giusta dipende dai tuoi clienti, dal tuo pricing, dai tuoi requisiti di conformita’ e dalle tue capacita’ operative.
La maggior parte dei prodotti SaaS dovrebbe iniziare multi-tenant. E’ piu’ economico, piu’ semplice e scala bene. Man mano che ti muovi verso l’alto mercato e inizi a vendere a organizzazioni piu’ grandi, aggiungi opzioni single-tenant per i clienti che ne hanno bisogno e pagheranno di conseguenza.
L’architettura dovrebbe servire il business, non il contrario. Costruisci per i clienti che hai oggi e progetta con flessibilita’ sufficiente per servire i clienti che vuoi domani.
Hai bisogno di aiuto per scegliere l’architettura giusta per il tuo prodotto SaaS? Abbiamo costruito sistemi multi-tenant e single-tenant in diversi settori. Troviamo l’approccio migliore per il tuo progetto.