Questo articolo confronta i modelli di tenancy Postgres più documentati (schema condiviso, base per tenant, cluster dedicato, chiamato anche database per tenant vs database condiviso), spiega il meccanismo noisy neighbor, quindi descrive in dettaglio come Aurabase implementa il proprio modello a due livelli, verificato nel codice del provisioner. Per la metodologia che applichiamo prima di pubblicare un dato relativo alle prestazioni, consulta la nostra metodologia di benchmark backend .
Se stai cercando la questione della perdita di dati tra due client (RLS, policy, service_role), questo non è l'argomento di questo articolo: il nostro Confronto RLS e database dedicato del progetto copre questo isolamento logico in dettaglio. Qui parliamo di risorse fisiche: CPU, IO, connessioni, cache.
L'essenziale
- Un database condiviso non è necessariamente uno schema condiviso: Aurabase fornisce ad ogni progetto il proprio database Postgres, anche ai livelli standard, condividendo solo il cluster.
noisy neighbordegrada le risorse fisiche (CPU, IOPS, connessioni, autovacuum), non la riservatezza dei dati: RLS non lo risolve, non è questo il suo ruolo.- Il provisioner Aurabase instrada esattamente verso due architetture, verificate nel codice:
FullyDedicated(intero cluster CNPG riservato per un progetto, livello aziendale) oSharedClusterDedicated(base dedicata sul cluster CNPG dell'organizzazione, mai condivisa con un'altra organizzazione). - Un cluster di flotta Aurabase ha una soglia di capacità osservata predefinita di 1000 basi per cluster, configurabile, oltre la quale si consiglia di migrare verso un cluster dedicato.
- La scelta giusta dipende dai tuoi vincoli reali (conformità, prevedibilità del traffico, budget), non da un riflesso “dedicato è sempre meglio”.
Tre modelli di gestione Postgres, dal più condiviso al più isolato
La documentazione ufficiale di Microsoft sull'architettura delle applicazioni SaaS multi-tenant distingue tre modelli di tenancy, generalmente chiamati Silo (risorse dedicate per tenant), Pool (risorse completamente condivise) e Bridge (una miscela dei due, alcuni tenant isolati, altri condivisi). Questi tre modelli si applicano direttamente a Postgres, a livello di schema, database o intero cluster.
Concretamente, per un backend Postgres, questo fornisce tre architetture distinte. Lo schema condiviso (una base unica, una colonna tenant_id, policy RLS che filtrano le righe) è il modello Pool più comune nelle guide multi-tenant: economico, ma il confine tra due client diventa un'espressione SQL valutata tabella per tabella. La base per tenant su un cluster condiviso è un modello Bridge intermedio: ogni tenant ha la propria base Postgres (un vero comando CREATE DATABASE), ma più basi coesistono sullo stesso cluster fisico, condividendo quindi CPU, IO e connessioni. Il cluster completamente dedicato per tenant è il modello Silo completo: risorse CPU, RAM e IO completamente isolate, generalmente riservate ai tenant con elevata conformità o problemi di carico.
| Modello | Isolamento delle risorse | Isolamento dello stoccaggio | Sforzo operativo |
|---|---|---|---|
| Schema condiviso (tenant_id + RLS) | Nessuno | Nessuno (tavolo comune) | Minimo (1 base per operare) |
| Per base tenant, cluster condiviso | Parziale (CPU/IO cluster) | Totale (su base propria) | Moderato (N basi, 1 cluster) |
| Cluster completamente dedicato per tenant | Totale | Totale | Alto (1 cluster per tenant) |
Terminologia Silo/Pool/Bridge: documentazione ufficiale Microsoft, pattern di architettura SaaS multi-tenant (Azure Architecture Center).
Il modello intermedio, base per tenant su cluster condiviso, è spesso assente nelle guide che presentano la scelta binaria tra “un'unica base per tutti” e “un server per client”. Tuttavia, questo è quello utilizzato da Aurabase per impostazione predefinita, descritto di seguito.
La scelta tra questi tre modelli si pone con ogni decisione relativa all'architettura multi-tenant, non solo con un fornitore BaaS: un team che costruisce il proprio backend SaaS su Postgres gestito (RDS, Cloud SQL o un'istanza self-hosted) effettua esattamente lo stesso arbitrato, con gli stessi meccanismi di contesa in gioco una volta che diversi client vengono posizionati sulla stessa istanza fisica.
Il vicino rumoroso: cosa si deteriora quando le risorse vengono condivise
Un noisy neighbor (vicino rumoroso) è un tenant che consuma una quota sproporzionata delle risorse condivise di un'infrastruttura, a scapito degli altri tenant sullo stesso server. Il termine deriva dal cloud pubblico, ma si applica direttamente a un cluster Postgres condiviso: un database può peggiorare le prestazioni di altri senza mai toccare i loro dati.
Sei meccanismi emergono più spesso nella produzione:
- Conflitto CPU: una query costosa (join senza indice, ordinamento massiccio) consuma cicli di CPU che il kernel condivide tra tutti i database attivi nel cluster.
- Conflitto IOPS: un backup, un
VACUUM FULLo un'importazione massiccia satura la velocità effettiva del disco del cluster, rallentando le letture e le scritture su altri database. - Esaurimento connessione:
max_connectionslimita il numero di connessioni attive a livello dell'intero cluster, non per base. Una base che si apre troppo riduce il margine degli altri. - Contesa di autovacuum: l'autovacuum viene eseguito con un numero limitato di lavoratori per cluster; un database con un'elevata velocità di scrittura può ritardare la pulizia delle tabelle di un altro database.
- Eliminazione della cache:
shared_buffersè una memoria singola per l'intero cluster; un database con un working set di grandi dimensioni può eliminare le pagine memorizzate nella cache di un database vicino più piccolo. - Finestre di manutenzione condivise: il backup, il failover della replica o l'aggiornamento principale si applicano all'intero cluster, non su base base.
Diagramma strutturale, non risultato di misurazione: finora non sono stati pubblicati dati comparativi sulle prestazioni per queste due topologie.
Il budget di connessione è spesso il sintomo più visibile nella produzione, anche prima della latenza. Questo è l'argomento dettagliato della nostra guida all'ottimizzazione max_connections e del nostro confronto tra PgBouncer, Supavisor e PgCat.
Un pooler in modalità transazione (PgBouncer, Supavisor, PgCat) mitiga l'esaurimento della connessione, ma non rimuove il conflitto di CPU o IOPS: riutilizza le connessioni del server esistenti, non aggiunge ulteriori core della CPU o throughput del disco al cluster. Il nostro articolo sulla modalità di pooling delle transazioni descrive in dettaglio cosa cambia effettivamente questa modalità e cosa non cambia.
RLS isola i dati, non le risorse
Row-Level Security risolve un problema diverso: impedisce a una query di leggere o modificare le righe di un altro tenant, a livello logico. Non riserva alcun ciclo della CPU, nessuno slot di connessione, nessuna velocità effettiva del disco per un tenant specifico.
Due inquilini possono avere politiche RLS perfettamente impermeabili e allo stesso tempo degradarsi a vicenda: il vicino rumoroso è un problema di risorse fisiche, non di diritti di accesso. Confondere i due porta a un falso senso di sicurezza operativa una volta che l’EPIRB è in atto.
Per l'isolamento logico (policy RLS, service_role, confine tra progetti lato sicurezza), consultare il nostro articolo dedicato: RLS e base dedicata per progetto, la scelta dell'isolamento multi-tenant da Aurabase. Questo articolo rimane al livello delle risorse fisiche.
Il modello Aurabase, verificato nel codice
Il codice del provisioner (aura-provisioner) documenta esattamente due possibili architetture per un progetto Postgres attivo, da un consolidamento del provisioning a cui il codice fa riferimento come Task 12: FullyDedicated e SharedClusterDedicated. I modelli legacy con granularità dello schema sono stati rimossi dal percorso di provisioning.
Il livello enterprise attiva FullyDedicated: un intero cluster CNPG, riservato a questo singolo progetto. Tutti gli altri livelli (gratuito, pro, team) vengono indirizzati a SharedClusterDedicated: un database Postgres project_<uuid> a tutti gli effetti, sul cluster CNPG dell'organizzazione del progetto. Non è quindi uno schema condiviso: anche su un piano standard, il tuo database è un database Postgres completo, non una riga tra le altre in una tabella comune. Ciò che viene condiviso è il cluster (CPU, RAM, disco, connessioni), non la base stessa.
Il cluster CNPG di un'organizzazione viene creato quando viene eseguito il provisioning del suo primo progetto Postgres e non ospita mai un progetto di un'altra organizzazione, una scelta di progettazione bloccata a livello di codice (org_cluster.rs, blocco consultivo Postgres per organizzazione alla creazione). L'unico possibile vicino rumoroso sul pianerottolo condiviso di Aurabase è quindi un altro progetto della propria organizzazione, mai quello di un cliente terzo.
Aurabase ha gestito le specifiche dell'architettura del cluster PostgreSQL.
Questa soglia di 1000 basi per cluster non è un limite rigido: è un benchmark di osservabilità che attiva una raccomandazione per la migrazione a FullyDedicated, non un blocco automatico. Non guida più alcuna decisione di posizionamento, ora è possibile un solo cluster per organizzazione.
Ogni cluster, dedicato o flotta, espone un CNPG Pooler (PgBouncer) che assorbe parte della pressione sulle connessioni attive, in entrambe le topologie. Ciò che effettivamente cambia questo pooler per il conflitto delle risorse è descritto in dettaglio di seguito.
Anche il dimensionamento CPU/RAM di un cluster condiviso non è uniforme tra le organizzazioni: deriva dal livello dell'organizzazione tramite una funzione dedicata (FleetSizing::from_org_plan, verificata in org_cluster.rs), e non da un'unica dimensione applicata a tutti i livelli. Un'organizzazione a livello di team non dimensiona il proprio cluster allo stesso modo di un'organizzazione a livello libero.
Queste due architetture funzionano su PostgreSQL 16, non sulla versione 17, verificata nel Dockerfile dell'immagine CNPG utilizzata in produzione. Questa scelta della versione ha le sue implicazioni di ottimizzazione, dettagliate nel nostro Confronto Postgres 16 vs 17 vs 18.
Quando basta il pooling, quando la dedicazione diventa necessaria
Il pooling non è un compromesso economico. Corrisponde al traffico della stragrande maggioranza dei progetti in fase di sviluppo, lancio o crescita moderata, dove un cluster dedicato rappresenterebbe un costo aggiuntivo senza beneficio misurabile.
| Segnale | Condiviso è sufficiente | Consigliato dedicato |
|---|---|---|
| Conformità formale sull'isolamento fisico (sanità, risorse umane, settore pubblico) | No | Sì |
| Traffico prevedibile, picchi moderati | Sì | |
| Carico di picco imprevedibile e prolungato | Rischio di restrizione | Sì |
| Budget ristretto, prodotto in fase di validazione | Sì | |
| Clausola contrattuale (DPA) che richiede un isolamento documentato | No | Sì |
Per i progetti soggetti a un obbligo contrattuale di isolamento fisico documentato, le nostre pagine DPA e conformità dettagliano ciò che copre ciascun livello.
Lo svantaggio del modello base per tenant, evidenziato da diversi strumenti di gestione della migrazione dello schema come Bytebase, è operativo piuttosto che tecnico: ogni migrazione deve essere applicata e verificata su ciascuna base, una per una, anche quando coesistono sullo stesso cluster. Un cluster completamente dedicato non elimina questo costo, anzi lo aggiunge: una migrazione per cluster da monitorare in modo indipendente, anziché una sola.
Le risorse specializzate in architetture software multi-tenant, come CodeOpinion, presentano regolarmente questo approccio intermedio (base per tenant su infrastruttura condivisa) come un compromesso ragionevole tra lo schema condiviso e il cluster completamente dedicato, piuttosto che una scelta binaria tra i due estremi.
Passare da condiviso a dedicato non richiede riscrivere uno schema o cambiare motore: in entrambi i casi, si tratta di Postgres, con la stessa catena pg_dump / pg_restore descritta nella nostra guida alla migrazione da Supabase ad Aurabase. La modifica del livello rimane un'operazione di commutazione, non una riscrittura dell'applicazione.
Domande frequenti
Cosa ricordare
Base dedicata e base condivisa non sono in conflitto sulla sicurezza dei dati: entrambi i modelli possono isolare correttamente un tenant da un altro a livello logico. Si oppongono tra loro sulle risorse fisiche (CPU, IOPS, connessioni, cache, finestre di manutenzione). È questo piano che definisce un vicino rumoroso, non una politica RLS scritta male.
Il modello Aurabase, verificato nel codice del provisioner, mantiene di default un compromesso intermedio: un database Postgres dedicato per progetto, su un cluster condiviso ma strettamente riservato a una singola organizzazione, con un cluster completamente dedicato riservato al livello business. La scelta giusta dipende dai vostri reali vincoli, non da una reflex dove la dedicata sarebbe sempre la soluzione migliore.