Come prendere la decisione di multi-tenancy che non si può facilmente invertire
Database condiviso con isolamento a livello di riga, schema-per-tenant o database-per-tenant. La scelta sbagliata è sopravvivibile per un po', poi non lo è più. Come prenderla deliberatamente.
La multi-tenancy è una delle poche decisioni architetturali SaaS che merita davvero la parola "irreversibile." Non strettamente irreversibile — ogni architettura può essere cambiata, con abbastanza denaro e una finestra di manutenzione — ma abbastanza costosa da cambiare che la maggior parte dei team che sceglie male convive con la scelta sbagliata per anni.
Le tre opzioni sono ben note: database condiviso con isolamento dei tenant a livello di riga, schema-per-tenant all'interno di un database condiviso, o database-per-tenant. La maggior parte degli articoli sull'argomento si ferma all'elencarle. La domanda interessante è quale si adatti a quale business, e la risposta dipende dalle proprietà dei propri clienti, non dalle proprietà del proprio codice.
Come appaiono davvero i tre modelli
Brevemente, per un vocabolario condiviso:
Database condiviso, isolamento a livello di riga. Un database. Uno schema. Ogni tabella ha una colonna tenant_id. Ogni query ha una clausola WHERE tenant_id = ?. L'isolamento dei tenant è applicato a livello applicativo. Questo è il default per la maggior parte dei prodotti SaaS ed è il più facile da costruire.
Schema-per-tenant. Un database. Uno schema separato per cliente. L'applicazione si connette con un search path o query qualificate per schema specifici del tenant. L'isolamento è applicato dal confine del database tra gli schemi. Backup, restore e migrazioni avvengono per schema.
Database-per-tenant. Un database separato per cliente. L'applicazione mantiene un pool di connessioni, sceglie il database giusto per la richiesta e instrada di conseguenza. L'isolamento è applicato dal confine più forte che il motore del database offre.
Esistono anche varianti — database condiviso con policy di sicurezza a livello di riga (Postgres RLS), modelli ibridi dove alcune tabelle sono condivise e altre per-tenant, e soluzioni gestite come Aurora Serverless o tabelle DynamoDB per-tenant. Il framework decisionale si applica anche a queste.
I quattro fattori che decidono
Quattro proprietà del proprio business determinano quale modello si adatta. La maggior parte dei team sopravvaluta il terzo e sottovaluta gli altri.
Distribuzione delle dimensioni dei tenant. Se i propri tenant sono di dimensioni approssimativamente uguali — piccole imprese che usano ciascuna forse 100MB di dati — il database condiviso funziona bene e la semplicità operativa è enorme. Se i tenant variano di tre ordini di grandezza — alcuni hanno 1MB, altri un terabyte — il database condiviso inizia a produrre piani di query patologici sui tenant piccoli perché le statistiche degli indici sono dominate da quelli grandi. Schema-per-tenant o database-per-tenant diventa strutturalmente migliore.
Rischio di noisy-neighbor. Alcuni carichi di lavoro dei clienti sono discontinui in modi che influenzano gli altri clienti. Una query di reporting che analizza l'intera storia di un tenant può bloccare il database condiviso se costruita male. In un modello condiviso, l'errore di un cliente degrada tutti. Il costo dell'isolamento è reale, ma lo è anche il costo del non averlo per clienti il cui lavoro è irregolare nel carico.
Vincoli normativi e contrattuali. Alcuni clienti firmeranno un contratto enterprise solo se i loro dati vivono in un database esclusivamente loro. Alcuni settori — sanità, servizi finanziari — rendono questa un'aspettativa predefinita piuttosto che un'eccezione. Se il team di vendita incontrerà questo nei prossimi due anni, costruire database condiviso ora significa una migrazione in seguito. La migrazione è la parte costosa dell'intera decisione architetturale.
Maturità operativa. Un database condiviso è una cosa sola da fare il backup, una cosa sola da aggiornare, una cosa sola da migrare. Mille database sono mille cose. Database-per-tenant funziona solo se la propria tooling operativa può trattare i mille come una flotta — provisioning automatizzato, patching automatizzato, verifica automatizzata dei backup, monitoraggio automatizzato dei costi. I team che scelgono database-per-tenant senza questa tooling annegano nelle operazioni entro un anno.
Il framework decisionale
Mappare i quattro fattori onestamente:
-
I tenant sono uniformi per dimensione, nessuna preoccupazione di noisy-neighbor, nessuna pressione normativa, team ops piccolo → database condiviso. Questa è la risposta giusta per la maggior parte dei SaaS nelle fasi iniziali.
-
I tenant variano di uno o due ordini di grandezza, alcuni sono abbastanza grandi da causare problemi di noisy-neighbor, nessuna pressione normativa → schema-per-tenant. Fornisce isolamento senza l'esplosione operativa di database separati.
-
I tenant includono clienti enterprise che richiedono isolamento a livello di dati, vincoli normativi in ambito, il team ops ha tooling per flotte → database-per-tenant. Spesso la risposta giusta per SaaS enterprise a vendita guidata, quasi sempre la risposta sbagliata per SaaS self-serve.
Il modello ibrido — alcuni condivisi, alcuni per-tenant — è spesso la destinazione reale dopo qualche anno di crescita. Non è un modello con cui iniziare. È il risultato di partire da un posto e scoprire che l'altro modello è giusto per un sottoinsieme specifico di clienti.
Cosa costruire ora anche se si cambia in seguito
Alcune abitudini rendono la migrazione eventuale meno costosa, qualunque modello si inizi.
Rendere l'ID del tenant un concetto di prima classe nel proprio modello di dominio dal giorno uno. Anche in un prototipo single-tenant, il modello dei dati dovrebbe averlo. Retrocompilarlo è doloroso; progettarlo dentro è gratuito.
Trattare il tenant scoping come un unico pezzo di codice, non una clausola WHERE sparsa ovunque. Un livello repository o query builder che inietta automaticamente lo scope significa che i bug di isolamento dei tenant diventano molto rari. Le query scritte a mano che "ricordano" di includere il filtro significano che i bug di isolamento dei tenant diventano inevitabili. Abbiamo visto denaro reale perso per questo.
Costruire la propria astrazione del connection pooling per supportare il routing per-tenant, anche se non la si usa. Quando arriva il giorno della migrazione, il cablaggio è già lì. Questo è uno degli investimenti anticipati più economici che si possono fare.
Eseguire un esercizio "quanto costerebbe la migrazione?" ogni sei mesi. Non perché si stia per farla, ma perché la risposta cambia man mano che il sistema cresce. Una migrazione che costerebbe una settimana oggi potrebbe costare un trimestre tra diciotto mesi. Conoscere il numero permette di scegliere di agire deliberatamente.
Il riassunto onesto
La scelta di multi-tenancy è genuinamente difficile, e merita genuinamente tempo. Non è una decisione che il team di ingegneria può prendere da solo — la risposta dipende da chi si vende e da come cambierà nei prossimi tre anni. Mettere la leadership vendite e la leadership ingegneria nella stessa stanza prima di decidere. I team che perdono denaro su questa decisione di solito lo perdono nella stanza dove la decisione era un default piuttosto che una discussione.
Vogliamo sentire le tue opinioni.
il nostro CTO Kyrylo Osadchuk risponderà entro 24 ore. Niente funnel di vendita.
Start a conversation
We want to hear your thoughts
Re: Come prendere la decisione di multi-tenancy che non si può facilmente invertire